请教 goroutine 通信写法问题

2022-08-17 18:22:21 +08:00
 chaleaochexist

第一种想法如上图: main goroutine 遍历这个 chan, 将所有数据读出. 但是问题是. 左边那三个 goroutine 如果结束了. main goroutine 如何结束? 岂不是阻塞了? 也没法关闭, 如果左边的其中一个关闭了. 那另外两个的数据就读不出来了.

第二种思路是创建三个 chan

这个直接 close 就行了.

我的问题是: 第一种想法中的问题如何解决?

是不是实践中第二种想法比较符合套路?

确实是新手. 大佬勿喷.

2576 次点击
所在节点    Go 编程语言
35 条回复
bruce0
2022-08-17 18:27:43 +08:00
第一个用 sync.waitGroup 应该能解决吧
ch2
2022-08-17 18:28:52 +08:00
waitgroup
chaleaochexist
2022-08-17 18:30:04 +08:00
@bruce0
@ch2

可以是可以. 那 chan 的 buffer 得足够大.要不然就死锁了吧?
qq1009479218
2022-08-17 18:31:48 +08:00
也可以再起一个 chan, 在想结束的时候通知 main 该结束了
chaleaochexist
2022-08-17 18:33:25 +08:00
@qq1009479218 明白了. 用 chan 或者 context
在主线程中用 select 检测那三个 goroutine. 好像可行. 不知道算不算最佳实践.
ch2
2022-08-17 18:39:11 +08:00
@chaleaochexist #3 我记得有第三方写的 infinite chan ,无限大缓冲区的 chan
lxdlam
2022-08-17 18:41:43 +08:00
Reading Material: https://go.dev/blog/pipelines

拆成两个问题:
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} }` 的形式来正确接受退出信号
lxdlam
2022-08-17 18:42:44 +08:00
@lxdlam 没有换行写的有点乱,最后一条 case 和 default 是不同的分支
qq1009479218
2022-08-17 18:46:51 +08:00
@chaleaochexist 三个 goroutinue 在想结束的时候发一个消息到用来结束的 chan 里,在 main 里面 select 监听,在监听到三次之后,说明三个 groutinue 全部执行完了,return main 就好了
这种方法,是其他协程通知主协程自己结束了,主协程收到这个通知,再决定下一步怎样做
而 context 其实是 main 协程管理其他协程的,就是 main 想让其他协程结束时调用 cancel ,其他协程通过监听 ctx.Done(),就可以 return 了
复杂并发应用中 goutinue 之间的关系,其实是树状的,你想在一个树的节点,结束这个数下面的所有的子 goroutinue 时,就用 context ,在子 goutinue 中传递值也可以
ilylx2008
2022-08-17 18:52:36 +08:00
你们真强,我都没看明白楼主在说啥。
jitongxi
2022-08-17 18:54:29 +08:00
一个 tcp 连接一个 goroutine , 结束, 不管客户端还是服务端都是。
加个 channel 就是脱裤子放屁
rrfeng
2022-08-17 20:10:59 +08:00
考虑下 main goroutine 为啥要结束??
chaleaochexist
2022-08-17 20:21:42 +08:00
@rrfeng 也不是一定要结束, 而是继续往下走.
nmap
2022-08-17 20:45:58 +08:00
第二种吧,逻辑清晰,实现简单
fds
2022-08-17 21:09:39 +08:00
nuk
2022-08-17 21:24:49 +08:00
往 channel 里写个结束的标记就行了吧,要不然就加个生存期管理
haoliang
2022-08-17 21:33:14 +08:00
第一种消耗比较小啊,可以考虑增加规定个独特的终止信息在生产端退出时发出,消费端识别处理下(比较类似于 waitgroup ,消费端处理终止信息时也可以用 atomic 计数)
joesonw
2022-08-17 22:52:55 +08:00
用 waitgroup 为什么会死锁?只是 routine 里因为 channel 满了,阻塞住,要等 channel 用空位了,才会塞入,然后继续运作。
chaleaochexist
2022-08-18 07:44:14 +08:00
@joesonw 三个生产者堵死. 因为 chan 满了.
消费者堵死, 因为一直在 wait.
joesonw
2022-08-18 09:19:02 +08:00
@chaleaochexist 都满了消费者怎么堵死,直接消费啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/873544

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX