goroutineの同時実行数を制限することができるpackageです。
golang.orgから提供されていますが、goのmainツリーとは別のプロジェクトになります。
そのため、使用するには、下記コマンドを実行してインストールする必要があります。
$ go get golang.org/x/sync/semaphore
下記例は、goroutineの同時実行を最大2つまでに制限します。
また、contextの生成が必須になります。
var sn = semaphore.NewWeighted(2) // goroutineの同時実行を最大2つまでに制限
func longProcess(ctx context.Context) {
if err := sn.Acquire(ctx, 1); err != nil { // 指定した同時実行数制限snから1つ実行権限を取得。上限に達していて取得できない場合は、取得でき次第、実行を開始
log.Fatalln(err)
}
defer sn.Release(1) // 最後にsn実行権限枠を1つ空ける
fmt.Println("start..")
time.Sleep(1 * time.Second)
fmt.Println("done")
}
func main() {
ctx := context.TODO() // contextの機能は今回利用しないため、TODOとする
go longProcess(ctx)
go longProcess(ctx)
go longProcess(ctx)
time.Sleep(4 * time.Second) // main関数が事前に終了してしまわないようsleep
}
上記例では、同時実行できないものについて、
semaphore.NewWeighted(i int).Acquire(ctx context, j int) error を用いて、
実行権限の枠が取得でき次第、実行を開始させました。
下記例では、同時実行できないものについては、処理を実行させないようにすることができます。
var sn = semaphore.NewWeighted(2)
func longProcess() {
if !sn.TryAcquire(1) { // 実行権限が取得できるかどうか、bool値を返す
fmt.Println("could not acquire")
return // 上限に達していて、実行権限が取得できない場合は処理を終了させる
}
defer sn.Release(1)
fmt.Println("start..")
time.Sleep(1 * time.Second)
fmt.Println("done")
}
func main() {
go longProcess()
go longProcess()
go longProcess()
time.Sleep(3 * time.Second)
go longProcess()
time.Sleep(2 * time.Second)
}
semaphore.NewWeighted(i int).TryAcquire(j int) boolの実行に際しては、
context.Contextは必要ありません。