Go言語

【Go言語】sync.WaitGroupとは?

Go言語学習中に遭遇したので、まとめておきます。

sync.WaitGroupのドキュメントには次のように書かれています。

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

訳してみると

「WaitGroupは複数のゴルーチンが終了するのを待つ。メインゴルーチンはAddメソッドを呼んで終了するのを待つゴルーチンの数を設定する。各ゴルーチンは終了するときにDoneメソッドを呼ぶ。並行して、すべてのゴルーチンが終了するまでブロックするために、Waitメソッドが使われる。」

要は、sync.WaitGroupは複数のゴルーチンを並行で実行するときに、全て終了するまで待つためのもの。

  1. メインゴルーチンで、終了するまで待ちたいゴルーチンの数だけAddを呼ぶ
  2. go文で生成されたゴルーチンで、終了するときにDoneを呼ぶ
  3. メインゴルーチンで、Waitを呼んで全てのゴルーチンが終了するまで待つ(ブロックする)

sync.WaitGroupはカウンターのようなもので、各メソッドは次のイメージ

  • Addメソッドは、インクリメント
  • Doneメソッドは、デクリメント
  • Waitメソッドは、カウンターが0になるまでブロックする

何となくイメージできるたので、サンプルコードを書いてみます。

サンプルコード

package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func main() {
	queue := make(chan string)
	// 3つのゴルーチンを生成
	for i := 0; i < 3; i++ {
		wg.Add(1) // ゴルーチン生成前にAddでインクリメントする
		go fetch(queue)
	}

	queue <- "http://example1.com"
	queue <- "http://example2.com"
	queue <- "http://example3.com"
	queue <- "http://example4.com"
	queue <- "http://example5.com"
	queue <- "http://example6.com"

	close(queue)
	wg.Wait()
	fmt.Println("All goroutines finished.")
}

func fetch(queue <-chan string) {
	for url := range queue {
		time.Sleep(10 * time.Second)
		fmt.Printf("%s finished!!\n", url)
	}
	// 処理が完了したらDoneでデクリメントする
	wg.Done()
	return
}

実行結果は次のようになりました。全てのゴルーチンの処理が終わった後に、「All goroutines finished.」が出力されて完了しています。

$ go run waitgroup.go
http://example2.com finished!!
http://example1.com finished!!
http://example3.com finished!!
http://example4.com finished!!
http://example6.com finished!!
http://example5.com finished!!
All goroutines finished.

ちなみに、sync.WaitGroupの処理を除いて実行すると次のように、途中で終了してしまいます。

http://example2.com finished!!
http://example3.com finished!!
http://example1.com finished!!
All goroutines finished.

以上!!

-Go言語

© 2021 フリエン生活 Powered by AFFINGER5