wg.Add() 放在哪里

var wg sync.WaitGroup

var v int32 = 0 

for i = 0; i < 100; i++{

   go func(){

       wg.Add(1) // wrong place

       atomic.AddInt32(&v,1)

       wg.Done()

   } 

}

wg.Wait()

fmt.Println(v)

这是我从该视频中看到的一段代码https://subscription.packtpub.com/video/application_development/9781788994880/97598/97608/goroutines


但是v总是小于100,我认为原因可能是wg.Wait()比预期更早结束,因为我们把wg.Add(1)匿名函数放在里面,并且在同一个 goroutinewg.Done()中会立即被调用,因此 main goroutine 从阻塞状态恢复执行。


但是如果我们将wg.Add(1)放入 for 循环中, v 将永远是100。


var wg sync.WaitGroup

var v int32 = 0 

for i = 0; i < 100; i++{

   wg.Add(1)

   go func(){

       atomic.AddInt32(&v,1)

       wg.Done()

   } 

}

wg.Wait()

fmt.Println(v)

我的问题是为什么我们可以保证 main goroutine 总是会在这里阻塞,使得 v 最终等于 100。如果在 for 循环之前添加一个任务到wg, 并且 main goroutine 在这里恢复执行,那是否可能,因为此时没有任务。


慕丝7291255
浏览 516回答 2
2回答

慕田峪7331174

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 的同时跳过,并且您的代码将保持正确。使用时要遵循的简单“规则”&nbsp;sync.WaitGroup:(引自this answer)在语句之前调用WaitGroup.Add()“原始”goroutine(开始一个新的)go建议调用WaitGroup.Done()deferred,所以即使 goroutine 发生恐慌它也会被调用如果你想传递WaitGroup给其他函数(而不是使用包级变量),你必须传递一个指向它的指针,否则WaitGroup(这是一个结构)将被复制,并且Done()不会观察到在复制上调用的方法在原版上

吃鸡游戏

就像其他人提到的那样wg.add(),应该在调用任何 go 例程之前调用。所以在主线程里面:一开始就推迟是一种很好的做法,这样你就不会忘记,因为它被视为清理行动。var wg sync.WaitGroupvar v int32 = 0&nbsp;for i = 0; i < 100; i++{&nbsp; &nbsp;wg.Add(1) //right place to put wg.add(1)&nbsp; &nbsp;go func(){&nbsp; &nbsp; &nbsp; &nbsp;defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp;atomic.AddInt32(&v,1)&nbsp; &nbsp;}&nbsp;}wg.Wait()fmt.Println(v)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go