LoginSignup
1
0

More than 5 years have passed since last update.

go での非同期処理 その2

Posted at

Go での非同期処理。まちあわせ。

前回 Go での非同期処理 その1でも、channel を使った待ち合わせの方法を実装したが、もっとちゃんとしたやり方がある様子。

WaitGroup を使う

WaitGroup というのを使うみたいだが、使うときと使わないときの比較をしてみよう。

package main

import(
    "fmt"
    "time"
)

func wait(i int) {
    time.Sleep(time.Second)
    fmt.Println(fmt.Sprintf("Wait %d done!", i))
}

func main() {
    for  i := 0; i < 3; i++ {
        go wait(i)
    }

    fmt.Println("Everything Done!")
}

こんなコードを書いてみる。当たり前だが、go routine が動くが、終わる前にメインの処理が終わってしまうので、次のような実行結果になる。

$ go run cmd/wait/*.go
Everything Done!

じゃあ、これをちゃんと、WaitGroup というやつに対応させてみよう。

package main

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

func wait(wg sync.WaitGroup, i int) {
    defer wg.Done()
    time.Sleep(time.Second)
    fmt.Println(fmt.Sprintf("Wait %d done!", i))
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go wait(wg, i)
    }
    wg.Wait()
    fmt.Println("Everything Done!")
}

基本は、WaitGroupを共有して、呼び元で、WaitGroup の Add メソッドを Go Routine の数だけ
呼んであげて、go routine の方で、Done() を呼び出せば、WaitGroup が終了を検知できるしくみになっている。さあ実行

W
io/WaitGo
$ go run cmd/wait/*.go
Wait 1 done!
Wait 0 done!
Wait 2 done!
fatal error: all goroutines are asleep - deadlock!

あかんがな、実行できているけど、Deadlock やがな。調べてみると、WaitGroup を渡すのに、実体を渡していると、関数にわたるときに、コピーされる。つまり、いくら Go Routine のほうで Done() を呼び出したところで、コピーのほうのDone() が呼ばれているだけで、元の、WaitGroup で足した Add の数が減ることがないという現象。じゃあ、ポインタ渡しにかえよう。

package main

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

func wait(wg *sync.WaitGroup, i int) {
    defer wg.Done()
    time.Sleep(time.Second)
    fmt.Println(fmt.Sprintf("Wait %d done!", i))
}

func main() {
    wg := &sync.WaitGroup{}
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go wait(wg, i)
    }
    wg.Wait()
    fmt.Println("Everything Done!")
}

実行結果

$ go run cmd/wait/*.go
Wait 0 done!
Wait 2 done!
Wait 1 done!
Everything Done!

無事待ち合わせ Done!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0