一尘不染

sync.WaitGroup 的示例是否正确?

go

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

阅读 212

收藏
2021-11-25

共1个答案

一尘不染

是的,这个例子是正确的。重要的是在语句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")
}

然而,wg.Add当你已经知道它会被调用多少次时,一遍又一遍地调用是没有意义的。


Waitgroups如果计数器低于零,则恐慌。计数器从零开始,每个Done()都是 a-1并且每个都Add()取决于参数。所以,为了保证计数器不会低于,避免恐慌,需要Add()进行担保来之前Done()

在 Go 中,这种保证由内存模型提供

内存模型指出,单个 goroutine 中的所有语句似乎都以与编写它们相同的顺序执行。它们实际上可能不会按该顺序排列,但结果就好像它是一样的。还保证goroutine 在go调用它的语句之后才会运行。由于 theAdd()出现在go语句之前并且go语句出现在 the 之前Done(),我们知道 theAdd()出现在 the 之前Done()

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

2021-11-25