哪里放wg.Add() [英] Where to put wg.Add()

查看:760
本文介绍了哪里放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)放在匿名函数中,并在同一goroutine中将立即调用 wg.Done(),因此主goroutine从阻塞状态恢复执行

but the v is always less than 100, I think the reason could be the wg.Wait() will over earlier than expectation because we put wg.Add(1) inside the anonymous function and in the same goroutine wg.Done() will be called immediately, thus main goroutine resume execution from blocked state.

但是,如果将 wg.Add(1)放入for循环中,则v始终为 100 .

But if we put the wg.Add(1) into the for loop, v will always be 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)

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

My question is why we can guarantee that main goroutine will always block here such that v will equal to 100 finally. Is that possible if before the for loop add one task to wg, and main goroutine resume execution here since there is no task at that moment.

推荐答案

在启动将调用 wg.Done()<的goroutine之前,应始终调用 wg.Add()./code>.

You should always call wg.Add() before you launch the goroutine that will call wg.Done().

在更正的示例中, main goroutine仅在 for 循环之后才能到达 wg.Wait(),以确保您调用 wg.Add()一百次,因此 wg.Wait()将阻塞,直到 wg.Done()被称为 100 次.

In your corrected example the main goroutine can only reach wg.Wait() after the for loop, which guarantees you call wg.Add() a hundred times, so wg.Wait() will block until wg.Done() is called 100 times.

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

When wg.Add() calls are in the new goroutines, there is no guarantee that any of the wg.Add() calls will be executed before the main goroutine reaches wg.Wait() since they run concurrently (without synchronization up until this point). The behavior in this case is non-deterministic (depends on the goroutine scheduler which is non-deterministic without explicit synchronization).

请注意,如果您知道循环执行了 100 次迭代,则另一种方法是在循环之前调用 wg.Add(100).我建议您不要这样做,因为当循环包含 break continue 操作时,这需要小心,这可能会导致启动goroutine的次数减少,从而最终导致您的 main 代码> goroutine卡住了.是的,在您的情况下,这可能是微不足道的,但是如果此代码随时间演变,则可能会变得不那么明显,并可能导致将来的错误.在场景中涉及启动goroutine时,说更快是无关紧要的.如果您仅在启动goroutine之前调用 wg.Add(1),则以后是否有条件跳过此部分都没有关系,因为您将跳过 wg.Add()以及启动goroutine,您的代码将保持正确.

Note that if you know your loop does 100 iterations, another alternative is to call wg.Add(100) before the loop. I advise against this practice though because this requires care when the loop contains break or continue operations, which might result in less goroutines launched and thus ultimately your main goroutine getting stuck. Yes, in your case this might be trivial, but if this code evolves in time, it might become less obvious and might result in future errors. Saying it's faster is irrelevant when launching goroutines is involved in the scenario. If you only ever call wg.Add(1) before launching a goroutine, it won't matter if later you conditionally skip this part, because you'll be skipping wg.Add() along with launching the goroutine, and your code will remain correct.

简单的规则"使用 sync.WaitGroup 时要遵循的步骤:(引自此答案)

  • 在其中调用 WaitGroup.Add() 原始"的在 go 语句
  • 建议致电 WaitGroup.Done() 延迟,因此即使goroutine恐慌也可以调用它
  • 如果您要将 WaitGroup 传递给其他函数(而不使用包级变量),则必须传递一个指向它的指针,否则传递 WaitGroup (即一个结构)将被复制,而在副本上调用的 Done()方法将不会在原始
  • 上被观察到
  • call WaitGroup.Add() in the "original" goroutine (that starts a new) before the go statement
  • recommended to call WaitGroup.Done() deferred, so it gets called even if the goroutine panics
  • if you want to pass WaitGroup to other functions (and not use a package level variable), you must pass a pointer to it, else the WaitGroup (which is a struct) would be copied, and the Done() method called on the copy wouldn't be observed on the original

这篇关于哪里放wg.Add()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆