V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
admirez
V2EX  ›  Go 编程语言

一般来说 chan 推荐用带缓冲的还是不带缓冲?

  •  
  •   admirez · 2018-03-15 07:26:27 +08:00 via iPhone · 1939 次点击
    这是一个创建于 2455 天前的主题,其中的信息可能已经有所发展或是发生改变。
    18 条回复    2018-03-17 10:38:37 +08:00
    janxin
        1
    janxin  
       2018-03-15 07:28:51 +08:00
    看需求...
    harry890829
        2
    harry890829  
       2018-03-15 08:50:56 +08:00
    搭车问下,我这边想用下协程池,是不是可以利用 chan 的阻塞机制?假设我 10 个协程都在等待 chan,chan 有内容自然就被协程读取了
    snail1988
        3
    snail1988  
       2018-03-15 09:22:49 +08:00
    协程就没必要池了吧,开销很低
    Reset
        4
    Reset  
       2018-03-15 10:09:18 +08:00
    @harry890829 10 个 goroutine 等待一个同一个 chan? 这样只会被某一个 goroutine 执行的
    harry890829
        5
    harry890829  
       2018-03-15 10:11:35 +08:00
    @Reset #4 是啊,这就是目的啊,生产者消费者嘛,我生产者不停的往 chan 加载,消费者 10 个 goroutine 等待 chan,如果 chan 有内容,是不是就被某一个 goroutine 读取,如果 chan 为空,则 goroutine 则进入阻塞状态?
    panyanyany
        6
    panyanyany  
       2018-03-15 10:16:24 +08:00
    @harry890829 #5 那你最好是用带缓冲的 chan,如果不带缓冲的话,你的其他 9 个 goroutine 会被堵住,写不进去。
    zzn
        7
    zzn  
       2018-03-15 10:18:43 +08:00
    @snail1988 开销是很低,但池化的一个好处是不会瞬间创建太多协程导致系统资源不足
    monnand
        8
    monnand  
       2018-03-15 10:35:59 +08:00 via Android
    不带缓存。这样方便收发双方同步。
    missdeer
        9
    missdeer  
       2018-03-15 10:41:09 +08:00
    @harry890829 就是这样
    Reset
        10
    Reset  
       2018-03-15 10:41:25 +08:00
    @harry890829 那你为什么不直接用一个 roroutine 接受 chan, 读取成功后在直接 起一个 goroutine 也可以

    for {
    e := <- ch
    go some_func(e)
    }
    harry890829
        11
    harry890829  
       2018-03-15 11:01:43 +08:00
    @snail1988 #3 还是弄个池吧,我这边外部消息进来不可控,担心量大的时候给冲垮,主要是考虑到协程中还会需要进行数据库、文件等操作,协程可能本身没问题,但是协程量过大把数据库拖垮了就 sb 了
    @panyanyany #6 现在准备用缓冲的 chan 来操作
    @Reset #10 恩恩,大致是这个意思,不过我需要控制 goroutine 的总量,goroutine 中会包含数据库操作,担心后来的操作有影响
    Reset
        12
    Reset  
       2018-03-15 12:04:42 +08:00
    @harry890829 那你也可以使用带容量的 channel 然后根据 len(ch) 加上 sync.WaitGroup 来实现, 不过你的方案如果能行的话效率应该是最高的
    虽然带容量, 在 ch 满了之后会依然是阻塞的, 会导致 producer 不能继续,
    之前做一个服务的时候有种场景 「 producer 可以不断的生产消息, 但是 consumer 需要限制消费速度」 channel 这个时候并是不很适用, 后来使用 slice 加 atomic 做的队列实现的
    JamesRuan
        13
    JamesRuan  
       2018-03-15 13:22:55 +08:00
    pool := make(chan chan Work, poolSize)
    stop := make(chan struct{})
    go func() {
    for {
    waitWork := make(chan work)
    select {
    case <-stop:
    return
    case pool <- waitWork:
    go func() {
    doWork(<-waitWork)
    close(waitWork)
    }()
    }
    }
    }()
    JamesRuan
        14
    JamesRuan  
       2018-03-15 13:24:43 +08:00
    如上。
    带 buffer 的 channel 天然就是一个 pool。
    harry890829
        15
    harry890829  
       2018-03-15 15:33:15 +08:00
    @Reset #12 恩恩,我生产者本身是 kafka 的消费者,所以阻塞的话应该问题不大,到时候我压测一下,结合生产数据量算算
    @JamesRuan #13 pool 是 chan chan 结构?我还没用过这东西,晚点研究研究
    admirez
        16
    admirez  
    OP
       2018-03-15 20:20:27 +08:00
    @JamesRuan 可是 buffer 满了的话 channel 就堵住了
    JamesRuan
        17
    JamesRuan  
       2018-03-17 10:36:54 +08:00
    @admirez 这个就是需求呀。
    buffer 不是为了不堵住的,而是为了控制堵住数量的。独占的话 buffer 就是 0,允许一个等待,buffer 就是 1。
    JamesRuan
        18
    JamesRuan  
       2018-03-17 10:38:37 +08:00
    @harry890829 chan chan 是好东西,外层 chan 带 buffer 排队,内层 chan 同步传具体数据。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6107 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:06 · PVG 10:06 · LAX 18:06 · JFK 21:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.