待機グループとは何ですか?次の記事では、Go 言語の WaitGroups を理解し、WaitGroups の使用方法を紹介します。
WaitGroups
は、ゴルーチンを同期する効率的な方法です。あなたが家族と一緒に車で旅行していると想像してください。あなたのお父さんは、食べ物を買ったり、トイレに行くために、ストリップ モールやファストフード レストランに立ち寄ります。 Horizon に向かう前に、全員が戻るまで待ったほうがよいでしょう。 WaitGroups
はこれを行うのに役立ちます。
WaitGroups
は、標準ライブラリの sync
パッケージを呼び出すことによって定義されます。
var wg sync.WaitGroup
それでは、WaitGroup
とは何ですか? WaitGroup
は、プログラムが待機する必要がある goroutine
の数に関する特定の情報を含む構造体です。これは、待機する必要がある ゴルーチン
の数を含むグループです。
WaitGroups には、Add
、Done
、Wait
という 3 つの最も重要なメソッドがあります。
コードの一部を見てみましょう:
package main import ( "fmt" "sync" "time" ) func main() { var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() fmt.Println(time.Now(), "start") time.Sleep(time.Second) fmt.Println(time.Now(), "done") }() wg.Wait() fmt.Println(time.Now(), "exiting...") }
2022-08-21 17:01:54.184744229 +0900 KST m=+0.000021800 start 2022-08-21 17:01:55.184932851 +0900 KST m=+1.000210473 done 2022-08-21 17:01:55.18507731 +0900 KST m=+1.000354912 exiting...
のインスタンス。
が完了するまで待機するため、
wg に 1 を追加します。
を実行します。
goroutine 内で、
wg.Done() への遅延呼び出しを行い、待機する
goroutine の数を確実に減分します。これを行わないと、コードは
goroutine が完了するまで永遠に待機することになり、デッドロックが発生します。
呼び出しの後、
WaitGroup が空になるまでコードをブロックする必要があります。これを行うには、
wg.Wait() を呼び出します。
はより直感的になる傾向があります。コードを読んで
WaitGroup が表示されると、そのコードが何をしているのかがすぐにわかります。メソッド名は明確で要点を捉えています。ただし、チャネルの場合、それがそれほど明確ではない場合があります。チャネルを使用するのは賢明ですが、複雑なコードを読むと理解するのが面倒になることがあります。
var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() fmt.Println(time.Now(), "start") time.Sleep(time.Second) fmt.Println(time.Now(), "done") }() } wg.Wait() fmt.Println(time.Now(), "exiting...")
goutine が他の
goroutine とデータ通信を行っていないことがわかります。
goroutine が 1 回限りのジョブであり、結果を知る必要がない場合は、
WaitGroup を使用することをお勧めします。ここで、次のコードを見てください:
ch := make(chan int) for i := 0; i < 5; i++ { go func() { randomInt := rand.Intn(10) ch <- randomInt }() } for i := 0; i < 5; i++ { fmt.Println(<-ch) }ここでは、
goroutine が
channel にデータを送信しています。このような場合、
WaitGroup は冗長になるため、使用する必要はありません。受信側ですでに十分なブロックが行われている場合、
goroutine が完了するまで待つ必要はありません。
WaitGroups は、
groutines の待機を処理するために特別に使用されます。チャネルの主な目的はデータを通信することだと思います。
WaitGroup を使用してデータを送受信することはできませんが、
channel を使用して
groutines を同期することはできます。
WaitGroups を使用することを好みますが、状況は異なる場合があります。最も直感的に感じられるものを選択してください。
WaitGroup インスタンスを
goroutine に渡す必要があります。異なる
goroutine を処理するために複数の
WaitGroup が存在する場合もあれば、設計上の選択である場合もあります。理由が何であれ、必ず次のように
WaitGroup にポインターを渡してください。
var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func(wg *sync.WaitGroup) { defer wg.Done() fmt.Println(time.Now(), "start") time.Sleep(time.Second) fmt.Println(time.Now(), "done") }(&wg) } wg.Wait() fmt.Println(time.Now(), "exiting...")その理由は、Go が値渡し言語であるためです。これは、関数に引数を渡すたびに、Go はその引数をコピーし、元のオブジェクトの代わりにそれを渡すことを意味します。この場合に起こることは、
WaitGroup オブジェクト全体がコピーされることです。つまり、
groutin はまったく異なる WaitGroup を処理することになります。
wg.Done() は、元の wg から減算するのではなく、
goutine にのみ存在するそのコピーを減算します。
WaitGroups
を使用すると、groutines
を簡単に同期でき、コードが正しい時間に実行されるようになります。チャネルは同期にも使用できますが、通常は WaitGroups
の方が直感的で読みやすいです。 WaitGroup
を使用する場合は、コピーの問題を防ぐために、ポインタを WaitGroup
に正しく渡してください。どの方法を選択する場合でも、最も直感的で、あなたとあなたのチームにとって最適なものを選択してください。
推奨学習: Golang チュートリアル
以上がGo 言語の WaitGroups とは何ですか?使い方?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。