这个示例用法sync.WaitGroup是否正确?它给出了预期的结果,但我不确定它wg.Add(4)的位置和位置wg.Done().一次添加四个goroutines是否有意义wg.Add()?
http://play.golang.org/p/ecvYHiie0P
package main
import (
"fmt"
"sync"
"time"
)
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
duration := millisecs * time.Millisecond
time.Sleep(duration)
fmt.Println("Function in background, duration:", duration)
wg.Done()
}
func main() {
var wg sync.WaitGroup
wg.Add(4)
go dosomething(200, &wg)
go dosomething(400, &wg)
go dosomething(150, &wg)
go dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
Run Code Online (Sandbox Code Playgroud)
结果(如预期):
Function in background, duration: 150ms
Function in background, duration: 200ms
Function in background, duration: 400ms
Function in background, duration: 600ms
Done
Run Code Online (Sandbox Code Playgroud)
Ste*_*erg 148
是的,这个例子是正确的.重要的是,wg.Add()在go声明之前发生以防止竞争条件.以下也是正确的:
func main() {
var wg sync.WaitGroup
wg.Add(1)
go dosomething(200, &wg)
wg.Add(1)
go dosomething(400, &wg)
wg.Add(1)
go dosomething(150, &wg)
wg.Add(1)
go dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
Run Code Online (Sandbox Code Playgroud)
但是,wg.Add当你已经知道它会被调用多少次时,反复调用是没有意义的.
Waitgroups如果计数器低于零,则会出现恐慌.计数器从零开始,每个Done()都是a -1,每个都Add()取决于参数.所以,为了保证计数器不会低于,避免恐慌,需要Add()进行担保来之前Done().
在Go中,这种保证由存储器模型给出.
内存模型表明单个goroutine中的所有语句似乎都以与写入时相同的顺序执行.它们可能实际上不是那个顺序,但结果就好像它一样.还保证goroutine在go调用它的语句之后才会运行.由于Add()在之前发生go语句和go之前的声明发生Done(),我们知道Add()前发生Done().
如果你要在go声明之前发表声明Add(),程序可能会正常运行.但是,这将是一种竞争条件,因为它不会得到保证.
mro*_*oth 26
我建议将wg.Add()调用嵌入到doSomething()函数本身中,这样如果调整调用它的次数,则不必手动单独调整add参数,如果更新一个参数但可能会导致错误,但忘记更新其他(在这个不太可能的简单示例中,但我个人认为这是更好的代码重用实践).
正如Stephen Weinberg在回答这个问题时指出的那样,你必须在产生gofunc 之前增加waitgroup,但是你可以通过将gofunc spawn包装在doSomething()函数本身中来轻松实现这一点,如下所示:
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
duration := millisecs * time.Millisecond
time.Sleep(duration)
fmt.Println("Function in background, duration:", duration)
wg.Done()
}()
}
Run Code Online (Sandbox Code Playgroud)
然后你可以在没有go调用的情况下调用它,例如:
func main() {
var wg sync.WaitGroup
dosomething(200, &wg)
dosomething(400, &wg)
dosomething(150, &wg)
dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
Run Code Online (Sandbox Code Playgroud)
作为一个游乐场:http://play.golang.org/p/WZcprjpHa_
小智 15
Run Code Online (Sandbox Code Playgroud)func dosomething(millisecs time.Duration, wg *sync.WaitGroup) { wg.Add(1) go func() { defer wg.Done() duration := millisecs * time.Millisecond time.Sleep(duration) fmt.Println("Function in background, duration:", duration) }() } func main() { var wg sync.WaitGroup dosomething(200, &wg) dosomething(400, &wg) dosomething(150, &wg) dosomething(600, &wg) wg.Wait() fmt.Println("Done") }