Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
101
Help us understand the problem. What is going on with this article?
@ruiu

sync.WaitGroupの正しい使い方

More than 5 years have passed since last update.

Goroutineを複数使って並列で処理を行って、それがすべて完了したら次に進みたいとしよう。Goroutineの完了はそれを生成したgoroutineに通知されるわけではないので、メインのgoroutineは何らかのメカニズムを使って全員が完了するまで待って、全員が完了したら実行を再開する必要がある。

sync.WaitGroupは複数のgoroutineの完了を待つための値だ(Javaを知っていれば、java.util.concurrent.CountDownLatchによく似ている)。WaitGroupの値に対してメソッドWaitを呼ぶと、WaitGroupが0になるまでWaitはブロックされる(待たされる)。従って、やりたい処理の数だけWaitGroupの値をインクリメントしておいて、処理完了時にデクリメントすれば、Waitを呼んで処理完了を待っているメインのgoroutineは、すべての処理が完了する(カウンタが0に戻る)まで待って、処理完了時に再開されるというわけだ。

というわけで概念的には単純なWaitGroupだが、マルチスレッドプログラミング特有の落とし穴があるので注意されたい。ありがちな間違いは、下のコードのように、新たに起動したgoroutineの中でWaitGroupをインクリメントしてしまうことだ。

wg := &sync.WaitGroup{}  // WaitGroupの値を作る
for i := 0; i < 10; i++ { // (例として)10回繰り返す
    go func() {
        wg.Add(1)  // wgをインクリメント
        // ここで何か処理を行う
        wg.Done()  // 完了したのでwgをデクリメント
    }()
}
wg.Wait()  // メインのgoroutineはサブgoroutine 10個が完了するのを待つ

上のプログラムは一見正しそうにみえる。Goroutineを複数起動しているが、子goroutineはまずwgをインクリメントして、完了時にデクリメントしているので、親のメインのgoroutineはすべての子が完了するまで待たされるはずだ ―― そうだよね?

しかし実際にはそうではない。Goroutineがスケジューリングされるタイミングは任意なので、goroutineが10個生成されて、しかしまだどれもまったく走っていないという状態がありえる。その状態でメインのgoroutineが最後の行に到達すると、wgは0(初期値)のままなので、メインのgoroutineはそのまま下に抜けてしまう。

このバグを直すには次のようにすればよい。いつ走るかわからないgoroutineの中でwgをインクリメントするのではなく、goroutineを起動する前にwgをインクリメントすればよいのである。

wg := &sync.WaitGroup{}  // WaitGroupの値を作る
for i := 0; i < 10; i++ { // (例として)10回繰り返す
    wg.Add(1)  // wgをインクリメント
    go func() {
        // ここで何か処理を行う
        wg.Done()  // 完了したのでwgをデクリメント
    }()
}
wg.Wait()  // メインのgoroutineはサブgoroutine 10個が完了するのを待つ

このようにすると最後の行は確実にすべてのgoroutineの完了を待つことになる。マルチスレッドプログラミングは意外な落とし穴があるが、これもその一つなので注意されたい。

101
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
101
Help us understand the problem. What is going on with this article?