Goの並行スレッドの実装:Go WaitGroupの最適化実装

Go言語では、並行ジョブスケジューラを作成するときにsync.WaitGroupを使用できます。WaitGroupは、同時に複数のタスクの完了を待つ簡単な方法を提供します。

大規模並列処理シナリオでは、WaitGroupはパフォーマンスの問題を引き起こす可能性があります。 Wait() メソッドを呼び出すたびに、すべての並列タスクが完了するまで現在のゴルーチンをブロックします。これにより過剰なゴルーチンが作成され、パフォーマンスが低下する可能性があります。

WaitGroup パフォーマンスを向上させるのには、バッファ付きチャネルを導入する方法がある。手順は下記の通り。

  1. プール
  2. 同期用WaitGroup
type Pool struct {
wg     sync.WaitGroup
worker chan struct{}
}
  1. プール
func NewPool(maxWorkers int) *Pool {
return &Pool{
worker: make(chan struct{}, maxWorkers),
}
}
  1. 追加する
  2. ウェイトグループ
func (p *Pool) Add() {
p.wg.Add(1)
p.worker <- struct{}{}
}
  1. 終了
  2. 待ち行列
func (p *Pool) Done() {
p.wg.Done()
<-p.worker
}
  1. 待つ()
  2. 同期 WaitGroup
func (p *Pool) Wait() {
p.wg.Wait()
}

最適化された Pool 構造体を使用することで、過剰な goroutine の作成を回避し、これにより並行処理の性能を向上させることができます。以下に完全なサンプル コードを示します。

package main
import (
"fmt"
"sync"
"time"
)
type Pool struct {
wg     sync.WaitGroup
worker chan struct{}
}
func NewPool(maxWorkers int) *Pool {
return &Pool{
worker: make(chan struct{}, maxWorkers),
}
}
func (p *Pool) Add() {
p.wg.Add(1)
p.worker <- struct{}{}
}
func (p *Pool) Done() {
p.wg.Done()
<-p.worker
}
func (p *Pool) Wait() {
p.wg.Wait()
}
func main() {
pool := NewPool(3)
for i := 0; i < 10; i++ {
pool.Add()
go func(i int) {
defer pool.Done()
time.Sleep(time.Second)
fmt.Printf("Task %d done\n", i)
}(i)
}
pool.Wait()
fmt.Println("All tasks done")
}

上記コードを実行すると、最大同時実行数3の同時実行ディスパッチャが作成され、10個のタスクの実行をシミュレートします。各タスクは1秒間スリープしてから完了メッセージを出力します。全てのタスクの完了を待った後、「All tasks done」が出力されます。

最適化されたPool構造体の利用により、並列スケジューリングのパフォーマンスを効果的に制御し、goroutineの過剰な生成を防止できます。

bannerAds