Go言語で並行処理を実装する場合は、これまでsync.WaitGroup
と同時実行数制御のsemaphore
を組み合わせて実装していました。しかし、errgroup
を使うことで、より簡潔に実装できることを最近知ったので、実装方法を簡単にまとめます。
本記事でためした環境のGo version: 1.22.0
errgroupの基本的な使い方
-
Go()
関数で並行処理を実行する -
Wait()
関数で全ての並行処理が終了するのを待つ -
SetLimit()
関数で同時実行数を制限
以下に例を記載します。
例
以下に基本的な例を示します。
package main
import (
"fmt"
"sync"
"golang.org/x/sync/errgroup"
)
func main() {
var g errgroup.Group
tasks := []func() error{
func() error {
// タスク1
fmt.Println("Task 1")
return nil
},
func() error {
// タスク2
fmt.Println("Task 2")
return nil
},
func() error {
// タスク3
fmt.Println("Task 3")
return nil
},
}
for _, task := range tasks {
g.Go(func() error {
return task()
})
}
if err := g.Wait(); err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Println("success!!!")
}
Task 3
Task 1
Task 2
success!!!
上記のコードでは、3つのタスクを並行して実行し、全てのタスクが完了するまで待ちつづけます。
SetLimit()による同時実行の制御
CPUなどリソースへの負担を避けたいときは、SetLimit()
を使用して同時実行数を制御することができます。
package main
import (
"fmt"
"golang.org/x/sync/errgroup"
"time"
)
func main() {
var g errgroup.Group
// 同時実行数を2に制限
g.SetLimit(2)
for i := range 5 {
g.Go(func() error {
fmt.Printf("Task %d started\n", i)
time.Sleep(2 * time.Second)
fmt.Printf("Task %d finished\n", i)
return nil
})
}
if err := g.Wait(); err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Println("success!!!")
}
Task 1 started
Task 0 started
Task 1 finished
Task 2 started
Task 0 finished
Task 3 started
Task 2 finished
Task 4 started
Task 3 finished
Task 4 finished
success!!!
この例では、5つのタスクがある中で同時に実行されるのは最大2つまでとなります。
分かりにくいですがOutputをみてみると、最初にTask1,0がスタートして、Task1が終了時にTask2がスタートしています。
ちゃんと同時実行数が2に制御されていますね。
for文で並列処理を行う際の注意点
go1.21以前では、forの各反復ではループ変数(iやv)が同じインスタンスを共有するため、for内のgoroutineに正しく変数を渡すことができません。
この問題についてはググるとたくさん出てくるので割愛します。
go1.22ではこの問題が解消されています。
内容は、以下リリースノートに詳しく記載されています。
https://tip.golang.org/doc/go1.22
もしgo1.21以前の場合は以下のように、loop変数を束縛する必要があります。
for i := range 5 {
i := i // 新しい変数'i'でloop変数'i'を束縛
g.Go(func() error {
fmt.Printf("Task %d\n", i)
return nil
})
}
最後に
今回は、Goのerrgroup
パッケージでの並行処理の実装について紹介しました。
弊社HRBrainでは、Goでのバックエンド開発が行われており、エンジニアの仲間を募集しています。
弊社に興味がある方は、ぜひHPだけでも見に来てください。