go 的 select 方法很适合 cache 啊 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
jpmorn
V2EX    Go 编程语言

go 的 select 方法很适合 cache 啊

  •  
  •   jpmorn 2017-12-24 09:41:35 +08:00 3818 次点击
    这是一个创建于 2853 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在这里看到的。https://mzh.io/%E4%B8%80%E4%BA%9BGolang%E5%B0%8F%E6%8A%80%E5%B7%A7

    在 nsq 中,需要读取之前磁盘上的,或者是从内存中直接读取,一般人都是先判断内存中有没有数据,然而,nsq 另辟蹊径使用了 select 语句,把 CSP 模式用到了极致。

    select { case msg = <-c.memoryMsgChan: //尝试从内存中读取 case buf = <-c.backend.ReadChan(): //如果内存中没有,直接从磁盘上读取 msg, err = decodeMessage(buf) if err != nil { c.ctx.nsqd.logf("ERROR: failed to decode message - %s", err) continue } 

    这个想法蛮好啊。

    25 条回复    2017-12-25 17:47:52 +08:00
    twm
        1
    twm  
       2017-12-24 09:51:27 +08:00 via iPhone
    go 是最好的语言,go 实现的网站
    www.cshome.com
    Muninn
        2
    Muninn  
       2017-12-24 10:13:58 +08:00
    这样写确实挺简洁的,比我的 if else 短一些。
    pathbox
        3
    pathbox  
       2017-12-24 10:20:33 +08:00 via iPhone
    你需要多开 channel 和 goroutine,这是占一些资源的 不过可以忽略。go 语言级别支持 csp,go 的 select 是在用户态中进行对 goroutine 的调度。
    xrlin
        4
    xrlin  
       2017-12-24 10:36:38 +08:00
    但是从 channel 中取出后,channel 中的消息已经没有了,这样还需要在消费后再将消息推送进 channel,并且还要自己维护失效时间。
    HXM
        5
    HXM  
       2017-12-24 10:37:04 +08:00 via Android
    @twm 乍一看域名以为是游戏相关的网站。。。
    jpmorn
        6
    jpmorn  
    OP
       2017-12-24 11:08:12 +08:00
    @xrlin 对的 这个是要自己再搞下。
    gamexg
        7
    gamexg  
       2017-12-24 11:12:41 +08:00   1
    go 并没有承诺 select 前面的高优先级,实测也发现并不是按照顺序确定优先级,而是乱序。

    ```

    package main

    import (
    "fmt"
    "time"
    )

    func main() {

    c1 := make(chan int, 10)
    c2 := make(chan int, 10)

    go func() {
    for i := 0; i < 100; i++ {
    c1 <- 1
    }
    }()
    go func() {
    for i := 0; i < 100; i++ {
    c2 <- 2
    }
    }()

    time.Sleep(100 * time.Millisecond)

    for {
    select {
    case i := <-c1:
    fmt.Println(i)
    case i := <-c2:
    fmt.Println(i)
    }
    }

    }

    ```

    输出结果:
    1
    2
    2
    2
    1
    2
    1
    1
    2
    1
    2
    2
    2
    1
    2
    1
    2
    2
    2
    2
    1
    1
    2
    1
    2
    1
    2
    1
    2
    1
    2
    2
    2
    2
    1
    1
    1
    2
    1
    2
    2
    1
    1
    2
    1
    1
    2
    2
    2
    1
    1
    2
    2
    2
    1
    2
    1
    2
    1
    2
    2
    2
    1
    pubby
        8
    pubby  
       2017-12-24 11:15:53 +08:00
    慎用,case 后面的都会被执行,本质上是在比哪个 case 更快返回

    func TestSelectCase(t *testing.T) {

    var fromCache = func() chan int {
    t.Log("call fromCache()")
    c := make(chan int, 1)

    <-time.After(time.Second * 1)
    c <- 1

    return c
    }

    var fromDB = func() chan int {
    t.Log("call fromDB()")
    c := make(chan int, 1)

    <-time.After(time.Second * 2)
    c <- 1

    return c
    }

    select {
    case <-fromCache():
    t.Log("got from cache")
    case <-fromDB():
    t.Log("got from db")
    }
    }

    select_case_test.go:11: call fromCache()
    select_case_test.go:21: call fromDB()
    select_case_test.go:34: got from db


    /////////////////////////

    func TestSelectCase(t *testing.T) {

    var fromCache = func() chan int {
    t.Log("call fromCache()")
    c := make(chan int, 1)

    go func() {
    <-time.After(time.Second * 1)
    c <- 1
    }()

    return c
    }

    var fromDB = func() chan int {
    t.Log("call fromDB()")
    c := make(chan int, 1)

    go func() {
    <-time.After(time.Second * 2)
    c <- 1
    }()

    return c
    }

    select {
    case <-fromCache():
    t.Log("got from cache")
    case <-fromDB():
    t.Log("got from db")
    }
    }

    select_case_test.go:11: call fromCache()
    select_case_test.go:23: call fromDB()
    select_case_test.go:36: got from cache
    sonyxperia
        9
    sonyxperia  
       2017-12-24 11:25:45 +08:00
    @twm 你给一个页面怎么看出来是 go 实现的
    pathbox
        10
    pathbox  
       2017-12-24 11:42:04 +08:00 via iPhone
    @pubby 所以 select 还要考虑 switch 的条件,case 的条件同一时刻只满足一个,如果同时满足多个 调度器选择执行哪一个都是有可能的
    jpmorn
        11
    jpmorn  
    OP
       2017-12-24 12:06:07 +08:00
    @pathbox 所以我说感觉就是这个场景的(缓存)下,这种设计还是很精妙的。
    TangMonk
        12
    TangMonk  
       2017-12-24 12:24:17 +08:00 via Android
    @gamexg 学到了,golang 文档好像没有写明
    pathbox
        13
    pathbox  
       2017-12-24 12:53:25 +08:00
    @jpmorn 有弊端。 当缓存和硬盘中都有数据的时候, 理论上是想从缓存读取,这样速度快,才起到缓存的作用,而却从硬盘取数据了,这样即使有缓存数据也没有起到作用。 所以 这种写法只适合非常简单的一种缓存机制,即使从硬盘取也不会很慢。 真要做大规模的缓存,不适合吧,当高并发的时候,会太多缓存失效的情况会发生,而实际中这些缓存数据都是有的
    pubby
        14
    pubby  
       2017-12-24 13:01:52 +08:00   1
    wweir
        15
    wweir  
       2017-12-24 13:22:07 +08:00
    这样做的前提是读压力小,读压力大的话,磁盘 io 直接就爆了
    6ufq0VLZn0DDkL80
        16
    6ufq0VLZn0DDkL80  
       2017-12-24 13:30:26 +08:00
    这代码逻辑有问题啊,有可能在有缓存的时候读盘,吹 go 不是这么吹的
    jpmorn
        17
    jpmorn  
    OP
       2017-12-24 13:32:25 +08:00
    @TangMonk @pubby 这里也有讲的。
    jpmorn
        18
    jpmorn  
    OP
       2017-12-24 13:33:13 +08:00
    @pathbox 唔~ 有道理~
    jpmorn
        19
    jpmorn  
    OP
       2017-12-24 13:34:05 +08:00
    @cholerae 读盘理论上应该比返回慢吧~读缓存应该先返回了
    Reset
        20
    Reset  
       2017-12-24 14:46:46 +08:00 via iPhone
    这个是看哪个 case 运气好被执行了
    stabc
        21
    stabc  
       2017-12-24 18:18:32 +08:00
    @twm 这个域名不做 CSGO 社区可以了……
    dumplinger
        22
    dumplinger  
       2017-12-25 09:39:59 +08:00
    select 的一个神坑就是多个 case 之间是无序的,当都有数值的时候会随机的返回其中一个 case,巨恶心。
    zhqy
        23
    zhqy  
       2017-12-25 11:03:07 +08:00   1
    代码逻辑没问题,建议看完整的代码。你贴的代码里那段中文注释错了,这里不是 if else,是 or 的关系。select 本身是无序的。
    jameshuazhou
        24
    jameshuazhou  
       2017-12-25 11:17:55 +08:00
    说 select-case 无序是坑的,官方文档早就说明得很详细了,而且这特性可以实现一些比较有意思的功能。
    敢问坑在哪里?
    sorra
        25
    sorra  
       2017-12-25 17:47:52 +08:00
    两个都是 channel,应该是谁刚好有数据就选谁。channel 不可能主动去查磁盘吧?应该要别的 goroutine 从磁盘查数据放进 channel。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3250 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 11:15 PVG 19:15 LAX 04:15 JFK 07:15
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86