此示例用法sync.WaitGroup正确吗?它给出了预期的结果,但我不确定wg.Add(4)的位置wg.Done()。一次添加四个goroutine是否有意义wg.Add()?
sync.WaitGroup
wg.Add(4)
wg.Done()
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") }
结果(按预期):
Function in background, duration: 150ms Function in background, duration: 200ms Function in background, duration: 400ms Function in background, duration: 600ms Done
是的,这个例子是正确的。重要的是在声明wg.Add()之前发生该事件go以防止出现种族状况。以下内容也是正确的:
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") }
但是,wg.Add当您已经知道将被调用多少次时,反复调用是没有意义的。
wg.Add
Waitgroups如果计数器降到零以下则恐慌。计数器从零开始,每个Done()为a -1,每个Add()取决于参数。所以,为了保证计数器不会低于,避免恐慌,需要Add()进行 担保 来之前Done()。
Waitgroups
Done()
-1
Add()
在Go中,这种保证由内存模型给出。
内存模型指出,单个goroutine中的所有语句似乎都按照与编写时相同的顺序执行。他们有可能实际上并不是按照这个顺序排列的,但结果似乎是这样。还可以确保goroutine直到go调用它的语句之后才运行。由于Add()发生在go语句之前,且go发生在语句之前Done(),我们知道Add()发生在语句之前Done()。
如果要让该go语句位于之前Add(),则该程序可能会正确运行。但是,这将是一种竞赛条件,因为无法保证。