非同期な処理

http://risky-safety.org/~zinnia/d/2009/06/#20090607-t0-h3-p4

私に関しては、いらなくね? と思ったことは記憶の近傍では無いように思います。似たようなこと何度も書いてる気がしますが、いい機会なのでちょっと自分の考えてることのうち、強く思っていることをまとめてみたいと思います。当たり前な感じの内容ですが。

現状、たぶん asynchronous な処理する時の道具って

  • select/epoll/kqueue ループ + callback
  • coroutine
  • thread
  • process

とあって、パフォーマンス的な観点を考えると前者2つはコア使い切れないので、パフォーマンスを考えないといけないソフトウェアがこの世から滅亡しない限り後者2つのどちらかは必要だと思っています。

thread vs process に関しては、よく process の方が起動が遅い、と言うわけですが、これはまぁ今となってはたぶんどうでも良い問題だと思っています(OSが賢くなった、所詮定数オーダーだからプロセッサが速くなって相対的に無視しやすくなった、スレッドでもしょっちゅう起こす必要がある場合は thread/prcess pool 作るに決まっている)。むしろメモリを手軽に共有できる、っていうのが thread の(めんどくさいところでもありますが)一番大きなメリットかなぁと思ってます。メモリ共有できるメリットは、通信のパフォーマンス的なコスト、通信の実装コスト、あたり。

一方、 process で良さそうなシーン、特に大きい単位で仕事を分割できるシーンでは色々な観点から process に軍配が上がることが多いように思います。色々な観点というのは、バグった時に他の単位に影響が出ない、(通信がめんどくさいので)プログラマが race が起きにくいプログラムを書くことを強制される、セキュリティ的な観点、プロセスはたまに殺してやればメモリフラグメンテーションが消える、などなど。全体的に fool proof 的な意味が多い気がします。複数マシンでの分散をするならどうせ process が必要、というのも。

さてパフォーマンスを無視して良いと考えて良いケースを考えると、上記に上げた上の2つも出てきます。これらについて私が強く思う論点は、使う際のめんどくささ、導入のめんどくささ、並列性、現状の開発環境によるサポート、あたりかなと思います。

使う際のめんどくささに関しては、 select loop はとにかくめんどくさい。適切なライブラリがあればかなりマシになるのですが、それでも asynchronous な処理が入るたびに手続き指向的な処理の流れが切れてしまうのがキツい。これが coroutine と thread と process なら手続き的に書けるので良いと思います。このへんに昔書きました。

http://shinh.skr.jp/m/?date=20080916#p01

導入は、 select loop は kernel/libc の primitive としては用意されてるものの、なんらかのライブラリを使わないと現実的にはキツいなぁという感じかと思います。 coroutine はそもそも無いと言って良いので、ライブラリを調達するところからです。 thread と process は最初からライブラリが完備されてると言って良い状況かと思います。

並列性。 thread と process はパフォーマンス上のメリットである並列性が問題起きた時の再現/デバッグのしにくさとして現われるので、まぁめんどくさいと思います。

開発環境のサポートは、まぁこれが一番重要なんじゃないかとか思うのですが、 thread や process は開発環境が整ってるので、ツールを使うという観点ではデバッグとかしやすいように思います。 process だと2つのプロセスにアタッチとかめんどいので、その観点では thread が一番いいくらいかも。 select loop は現状の開発環境では call stack が消えちゃう(非同期な処理が入るたびに一旦 callback を select loop に渡す)ので大変だと思います。 coroutine は他に同時に動いてる子の状況が見えないので大変。

あと coroutine は生成が軽いっていうメリットがあって、無数のオブジェクトが消えたり現われたりしまくる状況では状態を手軽に管理する手段としてはとても良いように思います。あとたぶん coroutine ってその状態の保存という観点では、他と完全に直行してなくて、 coroutine を大量生成しておいて thread pool がそれを適宜拾ってきてぶん回す、みたいなのができるなら良いなぁと思います。そういうライブラリは一度書いてみたい。 Erlang はたぶんそういう動作をしてるんだと理解してます。

忘れてることもあるかもだけど、まぁ私が重要だと思ってることはたいてい書いたような気がしました。 Zinnia さんがあげておられた Java Concurrency の本は評判が良いらしいので読もう読もうと思いつつ忘れてますね…いくない。たぶんよくできた thread pool ライブラリ的なものなのかなぁと理解してますが不明。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h