golang 中多个协程池如何优雅退出

2021-08-07 17:50:47 +08:00
 tim0991

假设有三个协程池(A,B,C), 三个分别处理不一样的业务且每个协程池中的 worker 数量不一致

当前数据流向为 A => B => C,任务在任一协程池中都有出现 err 导致该任务跳过的可能

在如下两种情况下:

最后在主程序中,针对上述两种情况,有没有优雅的办法知道任务已经全部完成且让主程序退出

2943 次点击
所在节点    Go 编程语言
23 条回复
tim0991
2021-08-08 17:34:14 +08:00
@nuk 和四楼的一个意思 单还是谢谢回复:)
zhengxiaowai
2021-08-09 10:06:25 +08:00
先说结论:要在 main 中感知任务的完成状态可以通过 chan,控制数据流转也是用 chan,如果有超时机制或者每个任务属性之类数据需要用到 context 。

1 )步骤大约是
main 函数中创建三个用于接受结果的 A B C chan,大小为 A 任务个数,和一个 notify chan 用于完成通知,再来一个通知主程序关闭的 doneChan

起一个 goruntine 去 for notify chan
go func() {
for a := range nChan {
if (ACount == BCount == CCount == 100) {
doneChan <- struct{}
}

}
}


起三个 goruntine 去 for 分别处理 A B C chan,里面写处理逻辑,大约是这样子
go func(nChan chan Notify) {
for a := range AChan {
// dosomething

if ok {
bChan <- weiboEntryID
} else {
nChan <- weiboEntryID
}
}
close(bChan)
}(nChan)

go func(chan Notify) {
for b := range BChan {
// dosomething

if ok {
cChan <- commentID
} else {
nChan <- commentID
}
}
close(cChan)
}(nChan)

go func(chan Notify) {
for c := range CChan {
// dosomething

if ok {
cChan <- commentUserID
} else {
nChan <- commentUserID
}
}
}(nChan)

这时候就 main 中可以往 AChan 里写数据了,写完直接 close AChan,然后直接用 doneChan 阻塞

for userID := range userIDs {
AChan <- userID
}
close(aChan)
<-doneChan


大致流程就是这样,需要注意的是需要正确关闭 ABC chan,就是在发送完成后关闭,nChan 用于任务信息回收还可以用于任务回放,另外为了保证每个任务都会返回,需要弄一个 timeout context 超时当作失败处理

2 )第二种情况,由于任务个数是未知的,上面的 100 就不能用了,有两种方式可以解决,一是可以预先知道每次数量,用另外的一个 chan 再任务开始时候传给发送 doneChan 那个 goruntine,把 100 改成最后总数即可。二是未知任务数量,这时候只能再来一个 chan,在做完 ABC 后发送一个 aDone 、bDone 、cDone,给发送 doneChan 那个 goruntine,当确认三个都完成后,就可以发送 done 了。

------

code 硬敲的可能很多不对,变量和具体结构可酌情改变 :-)
tim0991
2021-08-09 11:36:14 +08:00
@zhengxiaowai 谢谢回复 我还是觉得上面说的由协程池中的任务数量来判断是否已经完成简单一点

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

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

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

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

© 2021 V2EX