sync.WaitGroup的例子是否正确?

sync.WaitGroup这个示例用法sync.WaitGroup正确? 它给出了预期的结果,但我不确定wg.Add(4)wg.Done()的位置。 wg.Add()一次添加四个goroutines是否有意义?

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语句之前发生以防止竞争条件是很重要的。 以下内容也是正确的:

 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") } 

然而,当你已经知道调用多less次的时候,一次又一次地调用wg.Add是毫无意义的。


如果计数器下降到零以下, Waitgroups恐慌。 计数器从零开始,每个Done()-1 ,每个Add()取决于参数。 所以,你需要保证 Add()Done()之前来避免恐慌。

在Go中,这样的保证是由内存模型给出的。

内存模型指出,单个goroutine中的所有语句似乎都按照写入的顺序执行。 他们可能不会按照这个顺序,但结果会是如此。 这也保证了goroutine不会运行,直到go语句调用它 。 由于Add()出现在go语句之前,而go语句出现在Done()之前,所以我们知道Add()出现在Done()之前。

如果您在Add()之前有go语句,则程序可能正常运行。 然而,这将是一个竞争条件,因为它不能得到保证。

我build议将wg.Add()调用embedded到doSomething()函数本身,以便如果调整调用的次数,则不必手动分别调整add参数,这可能会导致错误你更新一个,但忘了更新另一个(在这个不太可能的例子,但我个人认为这是更好的代码重用的做法)。

正如Stephen Weinberg在回答这个问题时指出的那样,在产生gofunc 之前你必须增加waitgroup,但是你可以通过在doSomething()函数本身中包装gofunc产卵来完成这个任务,就像这样:

 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() }() } 

那么你可以在没有调用的情况下调用它,例如:

 func main() { var wg sync.WaitGroup dosomething(200, &wg) dosomething(400, &wg) dosomething(150, &wg) dosomething(600, &wg) wg.Wait() fmt.Println("Done") } 

作为一个游乐场: http : //play.golang.org/p/WZcprjpHa_