[勉強ノート] go 並列処理2

平行処理の構成要素

ゴルーチン(goroutine)

メイン関数もゴルーチン。ゴルーチンは他のコードに対し平行に実行している関数。

package main

import "fmt"

func sayHello() {
    fmt.Println("hello")
}

func main() {
    go sayHello()
}

簡単な例だが、これだとmain関数が先に終了してしまうので合流させる

package main

import(
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func sayHello() {
    defer wg.Done()
    fmt.Println("hello")
}

func main() {
    wg.Add(1)
    go sayHello()
    wg.Wait() // <= 合流ポイント
}

WaitGroup

平行処理の完了を待つ場合に有効

var wg sync.WaitGroup

wg.Add(1)
go func() {
    defer wg.Done()
    fmt.Println("first")
    time.Sleep(1)
}()

wg.Add(1)
go func() {
    defer wg.Done()
    fmt.Println("second")
    time.Sleep(1)
}()

wg.Wait()
fmt.Println("complete")

https://golang.org/pkg/sync/#WaitGroup

Mutex RWMutex

Mutexはメモリ(変数)へのアクセスを同期させる。RWMutexは読み込みと書き込みを別でロックする。

Cond

ゴルーチンが待機したりイベントの発生を知らせるために使う。

Once

syncの何らかのプリミティブを使ってDoメソッドに渡された関数はたとえ異なるゴルーチンで呼ばれたとしても1度しか実行されない。

Pool

今度勉強する。

channel

よく使いそうだから次の記事で詳しく書きたい。

ここら辺さらっとサンプル書かれててわかりやすかったです。
https://qiita.com/taizo/items/d73e54111bd470c1f1b3

 

どうやって平行処理を書いていくか?

  1. パフォーマンスクリティカルセクションか?
  2. データの所有権を移動しようてしているか?
  3. 構造体の内部状態を保護するか?
  4. 複数のロジックを協調させるか?

で見ていく。

1 yes => プリミティブを使う
2 yes => チャネルを使う
3 yes => プリミティブを使う
4 yes => チャネルを使う

パフォーマンスのクリティカルセクション

mutexを使った方がって書籍には書いてあったけど、パフォーマンスは良いがそんなに気にしなくても良いのかも・・・

基本channel使って良いよって記述されているっぽいからまずはchannelから詳しく学びたいと思う。

データの所有権の移動

結果を生成し、その結果を別の箇所で共有したい場合。

構造体の内部状態の保護

メモリアクセス同期を使うかどうかの分岐である場合。

type Counter struct {
    mu sync.Mutex
    value int
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

 

上記のIncrementの処理はアトミックであり、壁を超えてロックを公開するべきではない。ロックはレキシカルスコープ内に制限されるべき。

複数のロジックの協調

ロックや値を返すメソッドを組み合わせる場合。

結論、できる限りチャネルを使えば良い・・・?

 

コメントを残す

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