Goの軽量スレッド
Goroutineは裏ではOSのスレッドを利用するが、実装者がOS毎の違いを意識する必要はない。
シンプルにgo
と呼ぶだけで済む。
Goroutineはコルーチンでもある
コルーチンはプログラミングの構造の種類なので、他の言語に依存するものではない(Wiki)
GoのランタイムがGoroutineとOSスレッドの紐付け(スケジューリング, マルチプレキシング)を行い、Goroutineを軽量にしてくれている。
Rob Pikeの資料を元に解説する https://talks.golang.org/2012/waza.slide#6
英語ではParallel
Programming as the simultaneous execution of (possibly related) computations.
計算の同時実行としてのプログラミング
ランタイムの性質
英語ではConcurrency
Programming as the composition of independently executing processes.
ここで言うプロセスはlinuxのプロセスではなく、一般的なプロセス
Goは同時実行である並列性を担保している訳ではなく、独立に実行できるコンポーネントを組み合わせる並行性をサポートする。
Goroutineが並列(同時)に実行される保証はない
同時に実行される前提でコードを書くのは非推奨
一番シンプルな例
Goroutineにより並行で関数が呼び出される。
world helloの順で表示される。
Goroutineとmutexを使って、intのSortをする。
配列の要素の数字だけGoroutine内でSleepをするとSortをする事が出来る
Goroutineはメモリ空間を全Goroutineで共有する。
並列性は担保されないので少し微妙だけれど、分かりやすい例なので記載する
Goroutineで指定する関数のスコープで変数を定義していないので、forが進む毎に値が変わる
複数Goroutine間で同一のメモリにアクセスする時に使用する。
変数アクセスをThread Safeにする為の機構
例えばカウンタのインクリメントはMutexを用いる必要がある。
※ Mutexを用いずに関数やメソッドを用いる場合はThread Safeか確認する必要がある
mutexをLockする。
UnLockされるまで、他のGoroutineからのLock()呼び出しの完了はブロックされる。
このブロックにより、特定リソースへのアクセスが排他制御出来る。
mutexをUnLockする。
これにより他のGoroutineによるLockが可能になる。
deferでUnLockするのがお作法
sync.WaitGroupを用いると、Goroutineの完了を待つ事が出来る
複数のGoroutine(mainも含む)を同期させるのに使われる。
WaitGroupにはカウンタがあり、このカウンタをメソッド経由で操作してGoroutineの実行を待ち合わせする。
カウンタが0になるまでブロックする
カウンタをnumだけ増やす
カウンタを1減らす
準標準パッケージのerrgroup.Groupを使うと、Goroutineの完了同期だけでなく、Goroutine内で起こったエラーをハンドリング出来る。
SleepSortで100秒以上待つ場合は、長すぎるとしてエラーにする。
func() error
を満たす関数を受け取って、Goroutineを作る
全てのeg.Go()の完了を待つ。
いずれかのGoroutineでerrorが返された場合は、そのerrorを受け取る
Goroutineを使ってみる。
Sleep SortでWaitGroupを使って確実にGoroutineの実行完了を待てる様にしてください。
sleep_sort/main.go
を変更して、この課題を実装してください。
有名なGoの並行処理に関してよく纏まった書籍 https://www.oreilly.co.jp/books/9784873118468/
並行性と並列性の違いとGoについてのスライド https://talks.golang.org/2012/waza.slide#1