WaitGroupの基本的な使い方
Go言語のsync.WaitGroup
は、複数のgoroutineが終了するのを待つための機能を提供します。以下に基本的な使い方を示します。
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}
このコードでは、5つのworker goroutineを起動し、それらがすべて終了するのを待っています。各workerは、開始時にwg.Add(1)
を呼び出してWaitGroupのカウンタを増やし、終了時にwg.Done()
を呼び出してカウンタを減らします。wg.Wait()
は、カウンタが0になる、つまりすべてのworkerが終了するまでブロックします。これにより、すべてのworkerが終了するまでmain関数が終了しないようにすることができます。このように、sync.WaitGroup
は、複数のgoroutineの終了を同期するための強力なツールです。
複数のgoroutineでのWaitGroupの利用
複数のgoroutineを同時に実行し、それらがすべて終了するのを待つためには、sync.WaitGroup
を使用します。以下にその例を示します。
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers done")
}
このコードでは、5つのworker goroutineを起動し、それらがすべて終了するのを待っています。各workerは、開始時にwg.Add(1)
を呼び出してWaitGroupのカウンタを増やし、終了時にwg.Done()
を呼び出してカウンタを減らします。wg.Wait()
は、カウンタが0になる、つまりすべてのworkerが終了するまでブロックします。これにより、すべてのworkerが終了するまでmain関数が終了しないようにすることができます。このように、sync.WaitGroup
は、複数のgoroutineの終了を同期するための強力なツールです。
WaitGroupとchannelの組み合わせ
Go言語では、sync.WaitGroup
とchannel
を組み合わせることで、より複雑な並行処理を実現することができます。以下にその例を示します。
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "processing job", j)
results <- j * 2
wg.Done()
}
}
func main() {
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
go worker(w, &wg, jobs, results)
}
for j := 1; j <= numJobs; j++ {
jobs <- j
wg.Add(1)
}
close(jobs)
wg.Wait()
close(results)
for r := range results {
fmt.Println("result", r)
}
}
このコードでは、3つのworker goroutineを起動し、それらがjobs
チャネルからジョブを受け取り、結果をresults
チャネルに送信します。各workerは、ジョブがなくなるまでループし続け、ジョブを処理するたびにwg.Done()
を呼び出してWaitGroupのカウンタを減らします。wg.Wait()
は、すべてのジョブが終了するまでブロックします。これにより、すべてのジョブが終了するまでmain関数が終了しないようにすることができます。このように、sync.WaitGroup
とchannel
を組み合わせることで、複数のgoroutine間でのデータのやり取りと同期を同時に行うことができます。