如何等待多个 goroutine 完成?
Posted
技术标签:
【中文标题】如何等待多个 goroutine 完成?【英文标题】:How can wait for more than one goroutine to finish? 【发布时间】:2018-02-24 09:09:57 【问题描述】:package main
var fooRunning = false
var barRunning = false
func foo()
fooRunning = true
defer func() fooRunning = false ()
if barRunning
// wait for bar() to finish
...
func bar()
barRunning = true
defer func() barRunning = false ()
if fooRunning
// wait for foo() to finish
...
在我的情况下,如果我们运行go foo()
,它应该等待bar()
完成,反之亦然。最好的方法是什么?请注意,它们也可以独立执行。
【问题讨论】:
相关/可能与What's wrong with this golang code?重复 这些要求导致必须正确处理大量竞争条件(如果其他例程在您的正检查后立即结束怎么办?如果其他人在负检查后立即开始另一个例程等怎么办? . 如果有人运行 foo() 的 2 个例程怎么办?我强烈建议您创建一个更好的设计,让您没有 2 个相互依赖于另一个独立运行状态的 goroutine。 问题中的代码具有@nos 指出的设计死锁。没有适用于给定场景的解决方案。 【参考方案1】:任何具体的设计都无法安全地满足您的要求。按照规定,您说foo
和bar
可以 在并发 goroutine 中运行,并且如果其中一个或两个都已启动,则另一个应等待它们都完成。但是,这太弱了。如果foo
启动然后结束,但bar
还没有开始运行,会发生什么?如果bar
根本不运行怎么办?或者如果bar
运行,但foo
从来没有运行呢?
您是否要求foo
和bar
都必须启动和完成才能使您的程序正确?如果是这样,我可以猜到你的意思是:你想要一个 barrier 等待他们都完成后再继续。
package main
import (
"fmt"
"sync"
"time"
)
func foo()
fmt.Println("foo")
func bar()
fmt.Println("bar")
func within(wg *sync.WaitGroup, f func())
wg.Add(1)
go func()
defer wg.Done()
f()
()
func main()
var wg sync.WaitGroup
within(&wg, foo)
within(&wg, bar)
wg.Wait()
fmt.Println("Both foo and bar completed.")
(That same example in the Playground)
注意这里,foo
和 bar
都不是相互感知的;为了协调这两个呼叫,只有他们的呼叫者是。
您最初的尝试可能会导致您走上使foo
和bar
各自关闭或接受sync.WaitGroup
作为参数的道路,每个函数在退出之前首先是adding itself to the group 和waiting on it。那就是疯狂。
如果foo
在bar
有机会将自身添加到WaitGroup
之前启动并完成,则foo
将在bar
之前退出,即使您可以声称它们已经同时运行,或者反过来在foo
之前运行bar
可以注册其活动状态。同样,由于这是您程序的一个未明确说明的方面,我建议您转而关注更高级别的障碍,而不是这两个函数的相互依赖。
【讨论】:
我们应该总是为sync.WaitGroup传递指针。游乐场也有同样的建议。 谢谢,@SouravPrem。我根据您的建议更新了此处的文本和 Playground 链接。【参考方案2】:您可以使用频道!正如我从生锈的过程中所记得的那样,这会给:
func foo()
c := make(chan int)
go bar(c)
<-c
在酒吧里
func bar(c chan int)
// do stuff here
c <- 0
【讨论】:
如果 bar() 没有运行怎么办? Channel 会阻止进一步的执行,对吧? 是的,除非另一个 goroutine 在通道中推送一个整数,否则<-c
将阻塞,直到给出更多整数。如果您忘记在bar
中为通道提供整数,那么您的程序将陷入死锁
这仅提供单向阻塞,其中问题需要双向;它没有解决问题中设计的僵局;并且它不必要地使用了渠道。 sync.WaitGroup
正是为这个用例而构建的,但在从设计中消除死锁之前无法提出解决方案。以上是关于如何等待多个 goroutine 完成?的主要内容,如果未能解决你的问题,请参考以下文章