gpt4 book ai didi

go - wg.Add() 放在哪里

转载 作者:行者123 更新时间:2023-12-05 08:22:07 24 4
gpt4 key购买 nike

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) 放在匿名函数中,并且在同一个 goroutine 中 wg.Done() 将立即被调用,因此主 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 添加一个任务,并且主 goroutine 在这里恢复执行是否可能,因为此时没有任务。

最佳答案

在启动将调用 wg.Done() 的 goroutine 之前,您应该始终调用 wg.Add()

在您更正的示例中,main goroutine 只能在 for 循环之后到达 wg.Wait(),这保证您调用 wg.Add() 一百次,所以 wg.Wait() 将阻塞,直到 wg.Done() 被调用 100次。

wg.Add() 调用在新的 goroutine 中时,不能保证任何 wg.Add() 调用都会在 main goroutine 到达 wg.Wait() 因为它们同时运行(直到此时没有同步)。这种情况下的行为是不确定的(取决于 goroutine 调度程序,它在没有显式同步的情况下是不确定的)。

请注意,如果您知道循环执行 100 次迭代,另一种方法是在循环之前调用 wg.Add(100)。不过,我建议不要这样做,因为当循环包含 breakcontinue 操作时需要小心,这可能会导致启动的 goroutine 较少,从而最终导致你的 main goroutine 卡住了。是的,在你的情况下这可能是微不足道的,但如果这段代码及时发展,它可能会变得不那么明显,并可能导致 future 的错误。当场景中涉及启动 goroutines 时,说它更快是无关紧要的。如果您只在启动 goroutine 之前调用 wg.Add(1),那么稍后您有条件地跳过这部分也没关系,因为您将跳过 wg.Add() 同时启动 goroutine,您的代码将保持正确。

使用 sync.WaitGroup 时要遵循的简单“规则” :(引自 this answer)

  • 调用WaitGroup.Add()go 之前的“原始”goroutine(开始一个新的)中声明
  • 建议调用WaitGroup.Done() deferred,所以即使 goroutine panic 也会被调用
  • 如果你想将 WaitGroup 传递给其他函数(而不是使用包级变量),你必须传递一个指向它的指针,否则 WaitGroup(这是a struct) 将被复制,并且在副本上调用的 Done() 方法不会在原始
  • 上观察到

关于go - wg.Add() 放在哪里,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65213707/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com