A Tour of Go - Concurrency : 自分用リファレンスメモ

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

Goroutines

Goroutinesは軽量なスレッド。goと記述するだけで別スレッドで処理が実装される。

go f(x, y, z)

Channels

channelを使用してgoroutine間でデータの送受信を行える。

channelの生成
ch := make(chan int)
channelの送受信
ch <- v    // v をチャネル ch へ送信する
v := <-ch  // ch から受信した変数を v へ割り当てる

送受信の例。x, y := <-c, <-cでchannel cを2回受信するまで待つ。

func sum(c chan int) {
    c <- 10 // send sum to c
}

func main() {
    c := make(chan int)
    go sum(c)
    go sum(c)
    x, y := <-c, <-c // receive from c
    fmt.Println(x, y, x+y) // 10 10 20
}
Buffered Channels

channelはバッファのような使い方も可能。バッファが詰まった時は、チャネルへの送信をブロックする。別のgoroutineにchannelを渡す場合はバッファサイズは考慮されないみたい。

バッファファイズの指定

ch := make(chan int, 2)

バッファの送受信

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}
Range and Close

送り手は、送信する必要がなくなったチャネルを close できる。

func name(n int, c chan int) {
    c <- n
    close(c)
}

channelの状態確認

v, ok := <-ch

for i := range cでchannelが閉じられるまで受信を待ち続ける

func main() {
    c := make(chan int)
    go name(10, c)
    for i := range c {
        fmt.Println(i)
    }
}

Select

select は、複数あるcaseのいずれかが準備できるようになるまでブロックし、準備ができたcaseを実行する。複数のcaseの準備ができている場合、case はランダムに選択される。

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            //ここで一度ブロック
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    //select で c <- x: の条件が10回満たされる
    fibonacci(c, quit)
}
Default Selection

どの case も準備ができていないのであれば、 select の中の default が実行される。

select {
case i := <-c:
    // use i
default:
    // receiving from c would block
}

sync.Mutex

多分でJavaでいうsynchronizedのようなことができる。はず。

sync.Mutex.Locksync.Mutex.Unlockまでの処理はgoroutine間で直列に実行される。