[解決済み] sync.WaitGroupの例は正しいですか?
質問
この使用例は
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()
の前に記述すると、プログラムが正しく動作する可能性があります。しかし、それは保証されないのでレースコンディションになります。
関連
-
[解決済み】Goのタグはどのような用途に使われますか?
-
[解決済み】空のスライスを初期化する正しい方法
-
[解決済み] time.Sleepを使わずにすべてのゴルーチンが終了するのを待つには?
-
[解決済み] intをint64に変換するには?
-
[解決済み] ゴルーチンの停止方法
-
[解決済み] Goを使って大きなファイルを効率よくダウンロードするにはどうしたらいいですか?
-
[解決済み] GolangでMkdirを使ってネストされたディレクトリを作成するには?
-
[解決済み] interface{}をint型に変換する
-
[解決済み] Goで関数の名前を取得するには?
-
[解決済み] golangでは、マップから値のスライスを取得する良い方法はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] サーバーでSSLが有効になっていない
-
[解決済み] intをint64に変換するには?
-
[解決済み] Goを使って大きなファイルを効率よくダウンロードするにはどうしたらいいですか?
-
[解決済み] オブジェクトのプロパティを二重引用符で囲んで使用するには?
-
[解決済み] ログをファイルに書き出す方法
-
[解決済み] reflectを使用して、構造体フィールドの値を設定するにはどうすればよいですか?
-
[解決済み] Goプログラムで静的リソースをバンドルする最良の方法は何ですか?
-
[解決済み] Goで関数の名前を取得するには?
-
[解決済み] golangでは、マップから値のスライスを取得する良い方法はありますか?
-
[解決済み] スライスを変数入力として渡すには?