Sionの技術ブログ

SREとして日々の学習を書いて行きます。twitterは@sion_cojp

golang.org/x/sync/ を使ったGoの並列処理

はじめに

昔はsyncパッケージを使う必要があり、若干分かりづらいコードになってましたが、

golang.org/x/sync/ で実装すると分かりやすく改善されてたのでサンプルコードをおいてみます。

並列数は3に制限して実行するコードになってます。

syncパッケージのコード

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    num := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    wg := &sync.WaitGroup{}
    semaphore := make(chan struct{}, 3)

    for _, v := range num {
        wg.Add(1)
        semaphore <- struct{}{}
        go func(v int) {
            defer func() {
                <-semaphore
                defer wg.Done()
            }()
            Hoge(v)
        }(v)
    }
    wg.Wait()
}

func Hoge(i int) {
    fmt.Printf("start %v\n", i)
    time.Sleep(3 * time.Second)
    fmt.Printf("stop %v\n", i)
}

golang.org/x/sync/ のコード

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "golang.org/x/sync/errgroup"
    "golang.org/x/sync/semaphore"
)

func main() {
    num := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    sem := semaphore.NewWeighted(3)
    eg := errgroup.Group{}

    for _, v := range num {
        if err := sem.Acquire(context.Background(), 1); err != nil {
            fmt.Printf("failed to acquire semaphore: %v\n", err)
            break
        }
        v := v
        eg.Go(func() error {
            defer sem.Release(1)
            Hoge(v)
            return nil
        })
    }

    if err := eg.Wait(); err != nil {
        log.Fatal(err)
    }
}

func Hoge(i int) {
    fmt.Printf("start %v\n", i)
    time.Sleep(3 * time.Second)
    fmt.Printf("stop %v\n", i)
}