Got Some \W+ech?

Could be Japanese. Could be English. Android, セキュリティ, 機械学習などをメインに、たまにポエムったり雑感記載したりします。

明日Concurrencyについてm9(^Д^)プギャーられないための基礎知識

本記事はGo その2 Advent Calendar 2015の23日目の記事です。

Go言語どころかナンチャってプログラマーである私が、"Goの強みの一つにConcurrencyがあるんだぜ"とドヤ顔で友人に話した所、十分に理解しておらずm9(^Д^)プギャーられてしまいました。そんな被害者を増やさないために、調査したことを書きます。

目的

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の例

言葉は不要か。図示してみましょう。 * 以下は全て、Concurrency is not Parallelismの画像です

Gopherちゃん初めての焚書

一匹のGopherちゃんが積ん読された大量のマニュアルを焼却炉に破棄しようとしています。これにおける問題は「積読マニュアルを焼却する」といったことにあります。またこの問題を「実行」するのがGopherちゃんです。これをConcurrencyな構成(Concurrency Composition)にしてみましょう

Concurrencyな構成パターンA

この問題において「一部の積読マニュアルを拾って、運搬し、焼却炉で燃やす」といった単位でタスクを捉えるならば、もう一匹別のGopherちゃんと焼却炉を準備すれば、問題解決に向けた構成(concurrent composition)が設計できます。

このパターンでは、同じタスクを実行させる、というParallelismになっています。ただし、上記の構成ですと片方のGopherちゃんがサボったり、積読本の中のジャンプを読み始めたりする可能性もあります。つまり2匹のGopherちゃんが「同時実行しない」可能性があるということなので、何かしらの問題でParallelismではなくなることもあります(Conccurentではあり続ける)

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言語においては、その整理でよいのではないでしょうか。

おまけ: 色々なConcurrency vs Paralellism

参照