Go言語のWaitGroupを用いた複数の待機処理

By quonta 4月 18, 2024

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.WaitGroupchannelを組み合わせることで、より複雑な並行処理を実現することができます。以下にその例を示します。

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.WaitGroupchannelを組み合わせることで、複数のgoroutine間でのデータのやり取りと同期を同時に行うことができます。

By quonta

Related Post

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です