2 回答
TA贡献1828条经验 获得超13个赞
wg.Add()在启动将调用的 goroutine 之前,您应该始终调用wg.Done().
在您更正的示例中,maingoroutine 只能wg.Wait()在for循环之后到达,这可以保证您调用wg.Add()一百次,因此wg.Wait()会阻塞直到wg.Done()被调用100次数。
当wg.Add()调用在新的 goroutine 中时,不能保证任何wg.Add()调用都会在maingoroutine 到达之前执行,wg.Wait()因为它们是并发运行的(在此之前没有同步)。这种情况下的行为是不确定的(取决于 goroutine 调度程序,它在没有显式同步的情况下是不确定的)。
请注意,如果您知道循环100进行迭代,另一种选择是wg.Add(100)在循环之前调用。我建议不要这样做,因为当循环包含break或continue操作时,这需要小心,这可能会导致启动的 goroutine 更少,从而最终你的maingoroutine 会卡住。是的,在您的情况下,这可能是微不足道的,但如果此代码及时发展,它可能会变得不那么明显,并可能导致未来的错误。当场景中涉及启动 goroutine 时,说它更快是无关紧要的。如果您只wg.Add(1)在启动 goroutine 之前调用,那么稍后您是否有条件地跳过这部分也没关系,因为您将在wg.Add()启动 goroutine 的同时跳过,并且您的代码将保持正确。
使用时要遵循的简单“规则” sync.WaitGroup:(引自this answer)
在语句之前调用
WaitGroup.Add()“原始”goroutine(开始一个新的)go建议调用
WaitGroup.Done()deferred,所以即使 goroutine 发生恐慌它也会被调用如果你想传递
WaitGroup给其他函数(而不是使用包级变量),你必须传递一个指向它的指针,否则WaitGroup(这是一个结构)将被复制,并且Done()不会观察到在复制上调用的方法在原版上
TA贡献1829条经验 获得超7个赞
就像其他人提到的那样wg.add(),应该在调用任何 go 例程之前调用。所以在主线程里面:
一开始就推迟是一种很好的做法,这样你就不会忘记,因为它被视为清理行动。
var wg sync.WaitGroup
var v int32 = 0
for i = 0; i < 100; i++{
wg.Add(1) //right place to put wg.add(1)
go func(){
defer wg.Done()
atomic.AddInt32(&v,1)
}
}
wg.Wait()
fmt.Println(v)
- 2 回答
- 0 关注
- 566 浏览
添加回答
举报
