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_