1. ホーム
  2. go

[解決済み] sync.WaitGroupの例は正しいですか?

2022-09-21 05:44:29

質問

この使用例は sync.WaitGroup の使い方は正しいですか?期待される結果をもたらしますが、私は wg.Add(4) の位置と wg.Done() . で4つのゴルーチンを一度に追加するのは意味があるのでしょうか? 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 文の前に記述して、レースコンディションを防ぎます。また、以下のようにするのも正しいでしょう。

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()-1 であり、それぞれの Add() はパラメータに依存します。ですから、カウンターが決して下に落ちないようにし、パニックを回避するためには Add() にする必要があります。 保証 の前に来るように Done() .

Goでは、このような保証は メモリモデル .

メモリモデルでは、1つのゴルーチン内のすべての文は、書かれた順番通りに実行されるように見えるとされています。実際にはその順番でないこともありえますが、あたかもその順番であるかのような結果が得られます。また の後まで実行されないことが保証されています。 go ステートメントを呼び出した後まで . を呼び出すので Add() の前に発生するので go ステートメントと go ステートメントの前に発生する Done() の前にあることがわかると、私たちは Add() が発生する前に Done() .

もし、あなたが go 文の前に Add() の前に記述すると、プログラムが正しく動作する可能性があります。しかし、それは保証されないのでレースコンディションになります。