本記事はGo その2 Advent Calendar 2015の23日目の記事です。
Go言語どころかナンチャってプログラマーである私が、"Goの強みの一つにConcurrencyがあるんだぜ"とドヤ顔で友人に話した所、私の理解が半端すぎてm9(^Д^)プギャーられてしまいました。つらい。
そんな被害者を増やさないために、調査した内容とConcurrencyな構造パターンを書きます。
目的
Go言語におけるConcurrencyについて概要を理解する。
Concurrencyとは
なんなんでしょう。まずは日本語訳をググってみましょう。
concurrency: 同時並行性
なるほど。最初、私はconcurrency = 並列性だと考えていましたが、いきなり間違えてました。よく考えれば並列だったらparallelismになります。これはm9(^Д^)プギャーられるのも納得です。
次にParallelismもあわせて、その定義を探っていきましょう。
Concurrency vs Parallelism
The Go Blogにおいて下記のような記述がありました。
- concurrency is...
- about dealing with lots of things at once
- parallelism is...
- about doing lots of things at once
なるほど。わからん。もっと読みこんでみました
- Concurrency: Programming as the composition of independently executing processes
- 個々に実行されるプロセスの構成物
- ここでのプロセス≠Linuxプロセス である模様
- Parallelism: Programming as the simultaneous execution of computations
- 処理の同時実行
どうやら、Concurrencyは構成(structure)でありParallelismは実行(execution)である模様。もっと細かく言うと、Concurrencyは何かしらの問題を解決するための枠組みであり、問題を一つ一つ個々に実行可能なタスクへ落とし込む(プログラムの)構成手法のこと。一方、Parallelismはその枠組みを使った問題解決手法の一つです。本当かいな、と思いましたが、少なくともGoでの思想はそうなっているようですね。
Concurrencyの例
言葉は不要か。図示してみましょう。
- 以下は全て、[http://talks.golang.org/2012/waza.slide:title]の画像です
Gopherちゃん初めての焚書
一匹のGopherちゃんが積ん読された大量のマニュアルを焼却炉に破棄しようとしています。これにおける問題は「積読マニュアルを焼却する」といったことにあります。またこの問題を「実行」するのがGopherちゃんです。これをConcurrencyな構成(Concurrency Composition)にしてみましょう
Concurrencyな構成パターンA
この問題において「一部の積読マニュアルを拾って、運搬し、焼却炉で燃やす」といった単位でタスクを捉えるならば、もう一匹別のGopherちゃんと焼却炉を準備すれば、問題解決に向けた構成(concurrent composition)を設計できます。
このパターンでは同じタスクを実行させる、というParallelismになっています。ただし、上記の構成だと片方のGopherちゃんが積読本のジャンプを読み始めて、作業が中断される可能性もあります。つまり2匹のGopherちゃんが「同時実行しない」可能性もあるということなので、何かしらの問題でParallelismではなくなることもあります(Conccurent Compositionではあり続ける)
Concurrencyな構成パターンB
下記の図がConcurrencyな構成その2です。タスクを「積読マニュアルをカートに入れる」「運ぶ」「燃やす」といった単位で切り出し、それぞれのタスクをGopherちゃんが実行しています。ここでは、何かしらのトラブルがなければ、Gopherちゃん達は各々のタスクを同時実行しているのでParallelismが実現されているといえます。
Concurrencyな構成パターンC
下記の図はパターンBの発展形です。「運ぶ」タスクを細分化しており、「本が入ったカートを運ぶ」タスクと「空になったカートを運ぶ」タスク及び実行担当のGopherちゃんが追加されています。
Concurrencyな構成パターンD
今度はタスクを「積読本を中継地点まで運ぶ」タスクと「中継地点から焼却炉まで運んで燃やす」タスクにわけてみましょう。切り分け単位が焼却するまでの動作ではなく、積読マニュアルをどこまで運ぶかの距離となっています。
Concurrencyな構成パターンE
これはパターンAとパターンDの合わせ技です。片方の焼却炉が死んでも、もう片方の焚書ミッションは継続できるので、そちらでのParallelismは維持されます。
Concurrencyな構成パターンF
パターンA~パターンEをがっちゃんこしたやつ。Gopherちゃん、沢山必要です。可愛くてつらい。
現実に置き換えると
- 積読マニュアルたち -> webコンテンツ
- Gopherちゃん -> CPU
- カート -> レンダリング・ネットワーク等
- 焼却炉 -> ブラウザ等
まとめ
Concurrencyとは何かしらの問題に対するアプローチの仕方であり、設計であると言えます。その設計の仕方により、Parallelismを実装するかどうか、そしてどう実装するかが決定される、ということを理解しました。少なくともGo言語においては、その整理でよいのではないでしょうか。m9(^Д^)プギャーして頂けるコメント是非お待ちしております。