请教 goroutine 通信写法问题

讨论 未结 17 38
chaleaochexist
chaleaochexist 会员 2022年8月17日 11:18 发表
<p><img alt="image" class="embedded_image" loading="lazy" referrerpolicy="no-referrer" rel="noreferrer" src="https://user-images.githubusercontent.com/11831441/185095328-6e6e5542-0215-4c70-87eb-31a100b8a35e.png"></p> <p>第一种想法如上图: main goroutine 遍历这个 chan, 将所有数据读出. 但是问题是. 左边那三个 goroutine 如果结束了. main goroutine 如何结束? 岂不是阻塞了? 也没法关闭, 如果左边的其中一个关闭了. 那另外两个的数据就读不出来了.</p> <p>第二种思路是创建三个 chan <img alt="image" class="embedded_image" loading="lazy" referrerpolicy="no-referrer" rel="noreferrer" src="https://user-images.githubusercontent.com/11831441/185095723-e5222b37-f2c3-4ca3-8226-6558c203b4b1.png"></p> <p>这个直接 close 就行了.</p> <p>我的问题是: 第一种想法中的问题如何解决?</p> <p>是不是实践中第二种想法比较符合套路?</p> <p>确实是新手. 大佬勿喷.</p>
收藏(0)  分享
相关标签: 灌水交流
注意:本文归作者所有,未经作者允许,不得转载
17个回复
  • ch2
    2022年8月17日 11:18
    #3 我记得有第三方写的 infinite chan ,无限大缓冲区的 chan
    0 0
  • lxdlam
    2022年8月17日 11:18
    Reading Material: 拆成两个问题: 1. 多个 goroutine 如何读取消息 - 使用 fan-in 和 fan-out pattern ,将其结果汇总到一个 channel 里,此时原始 goroutine 关闭 channel 不影响; - 直接 select 多个 channel 。 2. 当某个 gorutine 退出时如何通知其他的 goroutine 退出: a. (可选)如果需要等待其他 goroutine 退出的话,使用 sync.WaitGroup 等待; b. 使用一个 exitChannel ( chan struct{} 就行),接收到退出信号的时候直接由 main close ,其他 goroutine 使用 `for { select { case <- exitChannel: return default: logic} }` 的形式来正确接受退出信号
    0 0
  • lxdlam
    2022年8月17日 11:18
    没有换行写的有点乱,最后一条 case 和 default 是不同的分支
    0 0
  • qq1009479218
    2022年8月17日 11:18
    三个 goroutinue 在想结束的时候发一个消息到用来结束的 chan 里,在 main 里面 select 监听,在监听到三次之后,说明三个 groutinue 全部执行完了,return main 就好了 这种方法,是其他协程通知主协程自己结束了,主协程收到这个通知,再决定下一步怎样做 而 context 其实是 main 协程管理其他协程的,就是 main 想让其他协程结束时调用 cancel ,其他协程通过监听 ctx.Done(),就可以 return 了 复杂并发应用中 goutinue 之间的关系,其实是树状的,你想在一个树的节点,结束这个数下面的所有的子 goroutinue 时,就用 context ,在子 goutinue 中传递值也可以
    0 0
  • ilylx2008
    2022年8月17日 11:18
    你们真强,我都没看明白楼主在说啥。
    0 0
  • jitongxi
    2022年8月17日 11:18
    一个 tcp 连接一个 goroutine , 结束, 不管客户端还是服务端都是。 加个 channel 就是脱裤子放屁
    0 0
  • rrfeng
    2022年8月17日 12:16
    考虑下 main goroutine 为啥要结束??
    0 0
  • nmap
    2022年8月17日 12:49
    第二种吧,逻辑清晰,实现简单
    0 0
  • nuk
    2022年8月17日 13:47
    往 channel 里写个结束的标记就行了吧,要不然就加个生存期管理
    0 0
  • haoliang
    2022年8月17日 13:47
    第一种消耗比较小啊,可以考虑增加规定个独特的终止信息在生产端退出时发出,消费端识别处理下(比较类似于 waitgroup ,消费端处理终止信息时也可以用 atomic 计数)
    0 0
  • joesonw
    2022年8月17日 15:18
    用 waitgroup 为什么会死锁?只是 routine 里因为 channel 满了,阻塞住,要等 channel 用空位了,才会塞入,然后继续运作。
    0 0
  • seth19960929
    2022年8月18日 03:48
    close chan 两个原则 1. 不要在接收端关闭, 也就是你代码里的 main goroutine 2. 有多个同时写, 不要在写的地方关闭, 也就是你的代码中 goroutine1,2,3 所以最好的做法, 就是楼上给的那个代码, 先 waitGroup 够三个之后, 直接在 main 关闭就行了
    0 0
  • seth19960929
    2022年8月18日 03:48
    package main import ( "fmt" "math/rand" "sync" "time" ) func main() { // init var ch := make(chan int) wg := &sync.WaitGroup{} // goroutine1, 2, 3 for i := 0; i < 3; i++ { wg.Add(1) go task(wg, ch) } // read chan data go func() { for val := range ch { fmt.Println(val) } }() // wait group wg.Wait() close(ch) // close fast, can`t read all chan data time.Sleep(time.Second) } func task(wg *sync.WaitGroup, ch chan int) { defer wg.Done() ts := rand.Intn(3) + 1 time.Sleep(time.Second * time.Duration(ts)) ch <- ts }
    0 0