Goによるサンプル: ワーカープール

このサンプルでは、goroutineとチャネルを使用して、ワーカープールを実装する方法について説明します。

package main
import (
    "fmt"
    "time"
)

ワーカーを以下のように記述します。ワーカーの数個の同時のインスタンスを実行します。これらのワーカーはjobsチャネルで作業を受け取り、対応する結果をresultsで送信します。作業の内容が複雑であることをシミュレートするために、ジョブごとに1秒スリープします。

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        results <- j * 2
    }
}
func main() {

ワーカーのプールを使用するには、ワーカーに作業を送信して、その結果を収集する必要があります。これには2つのチャネルを作成します。

    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

この時点でワーカーが3つ起動しますが、まだジョブが登録されていないのでブロックされています。

    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

ここで、5つのジョブを送信してから、それ以上作業がないことを示すためにそのチャネルをcloseします。

    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

最後に、作業のすべての結果を収集します。これにより、ワーカーgoroutineが終了したことも保証されます。複数のgoroutineを待機する別の方法は、WaitGroupを使用することです。

    for a := 1; a <= numJobs; a++ {
        <-results
    }
}

プログラムを実行すると、5つのジョブがさまざまなワーカーによって実行されていることがわかります。プログラムでは総計で約5秒の作業が行われますが、3人のワーカーが同時に作業しているので、わずか約2秒しかかかりません。

$ time go run worker-pools.go 
worker 1 started  job 1
worker 2 started  job 2
worker 3 started  job 3
worker 1 finished job 1
worker 1 started  job 4
worker 2 finished job 2
worker 2 started  job 5
worker 3 finished job 3
worker 1 finished job 4
worker 2 finished job 5
real    0m2.358s

次のサンプル: WaitGroups