2 回答
TA贡献1828条经验 获得超13个赞
wg.Add()
在启动将调用的 goroutine 之前,您应该始终调用wg.Done()
.
在您更正的示例中,main
goroutine 只能wg.Wait()
在for
循环之后到达,这可以保证您调用wg.Add()
一百次,因此wg.Wait()
会阻塞直到wg.Done()
被调用100
次数。
当wg.Add()
调用在新的 goroutine 中时,不能保证任何wg.Add()
调用都会在main
goroutine 到达之前执行,wg.Wait()
因为它们是并发运行的(在此之前没有同步)。这种情况下的行为是不确定的(取决于 goroutine 调度程序,它在没有显式同步的情况下是不确定的)。
请注意,如果您知道循环100
进行迭代,另一种选择是wg.Add(100)
在循环之前调用。我建议不要这样做,因为当循环包含break
或continue
操作时,这需要小心,这可能会导致启动的 goroutine 更少,从而最终你的main
goroutine 会卡住。是的,在您的情况下,这可能是微不足道的,但如果此代码及时发展,它可能会变得不那么明显,并可能导致未来的错误。当场景中涉及启动 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 关注
- 515 浏览
添加回答
举报