[Go] Go言語による並行処理 3章メモ1
Go言語による並行処理の第3章をまとめていく。 www.amazon.co.jp
3.1 ゴルーチン
関数呼び出しの前にgo
キーワードを置くことでゴルーチンを起動できる。
func main() { go f() ... } func f { ... }
3.2 syncパッケージ
3.2.1 WaitGroup
Addでカウンターを1増やし、Doneで1減らす。Waitを呼び出すとカウンターがゼロになるまでブロックする。
var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() ... } wg.Wait()
3.2.2 MutexとRWMutex
プログラム内のクリティカルセクションを保護する。
以下の例の場合、変数a
を保護、その解除を行っている。
var a int var lock sync.Mutex ... go func() { lock.Lock() defer lock.Unlock() a++ } ...
RWMutexは読み込みと書き込みを区別することができる。Lockは上のMutexでのLockと同様、読み書き両方をロックする。RLockは書き込みのみをロックし、読み込みは可能となる。
var lock sync.RWMutex
lock.RLock()
lock.RUnlock()
lock.Lock()
lock.Unlock()
3.3 Cond
イベントの待機や発生を知らせる。
c := sync.NewCond(&sync.Mutex{}) func f() { c.L.Lock() // クリティカルセクションを操作する処理 c.L.Unlock() c.Signal() } func main() { c.L.Lock() for conditionTrue() == false { c.Wait() } // クリティカルセクションを操作する処理 go f() c.L.Unlock() }
sync - Go 言語において、Waitは
自動的に c.L のロックを解除し,呼び出し側のゴルーチンの実行を中断します。 後で実行を再開した後, Wait は c.L をロックしてから戻ります。
これを上の例で見ると以下のようになる。
conditionTrue()
がfalseになったら、ループに入り、c.Wait()
を呼び出すことで呼び出し側(main関数)の処理を一旦停止し、c.Lのロックを解除する。- 関数fでクリティカルセクションを操作する処理が行われ、
c.Signal()
を実行することで、c.Wait()
で停止されていたmain関数の処理が再開される。その際、main関数でc.Lが再びロックされる。 conditionTrue()
がfalseのままであったら、1に戻り、trueであったらループから抜け出し、その後の処理を行う。
c.Broadcast()
ではc.Wait()
となっているすべてのゴルーチンにシグナルを伝える。
3.2.4 Once
sync.Once.Do
は一度しか呼び出されない。
Pool
使うものを決まった分だけ作る方法。
Get
メソッドではプールに必要なインスタンスがあるか確認し、あれば呼び出し元にそれを返す。なければ、New
を呼び出した結果を返す。作業が終わるとPut
メソッドを用いて使っていたインスタンスをプールに返す。