プログラムの動作を早くする並列的(concurrent)アプローチ

(考えたことを書いてみる。正直書いてあることは自明なので役に立つようなものではありません。)

はやさを求めて

プログラムにしても、人手による作業にしても、作業にかかる時間を短縮しようとしたら以下のようなことをだいたいやるでしょう。

  • 作業を減らす、あるいは効率的な方法に変更する
  • 個々人の能力を最大まで引き上げる
  • 作業を並列化する

最近のCPUのメニーコア現象だと最後の作業を並列化するというのがトレンドになってきています。
プロジェクト進行でもそうですが、プロジェクト開発はシングルライン(シングルスレッド)ではありません。マルチプロセス、マルチスレッド*1です。要するに多数の物事が並列して動きます。もちろん効率化のためです。

並列のトラブル

確かに並列化させると物事はスピーディに動き始めます。ただ、シングルラインで動かしていたときよりずっとトラブルは多くなります。

既に作業がある程度効率化されている場合、並列化以外の高速化手段を取れないのが現実です。もろに最近のメニーコア流行の方向です。

並列となかよくなろう

並列すれば速くなる、でも、並列を意識してプログラミングもしくはするのは大変だということで、いくつか付き合う方法があります。

  1. C言語的手続き言語で安全なAPIを使いつつ、罠をさけながらデザインパターンや伝統に沿い並列を自発的に作り出す。
  2. クリティカルパスにつながる論理的関係を示すだけで、並列化可能ポイントを機械的に搾り出し、とりあえずの並列化を促す。
  3. 共有資源、情報交換を無くす。

最初はJavaのスレッド、2番目にあたるのはHaskell型のモナドのアプローチ、最後のはErlangのマルチプロセスのアプローチかな。

Javaのような言語でも処理ブロック間の依存性を記述するだけで勝手に並列化するように書けないかな、と思います。単なるAPIの組み合わせであれば、書けないことは無いと思います。いつか書いてみよう。

(要するに一連の高速化が必要なバッチ処理などがあった場合、依存性の無い処理に関してはどんどん非同期にぶっとばしてしまえば速度が多少あがるというわけです。最近のLinuxだったけかも、デバイスの初期化をどんどん非同期にしていますよね。基本的に物事の順序が関係ないものはどんどん非同期でぶっ放していいわけです。)

数年後のCPUはもっとメニーコアになっているでしょう。そして高速なプログラムの条件に、自分のタスクのクリティカルパスについて知り尽くしている、という条件が強く加わるはずです。(GPGPUなんかもこういう流れの一端なのかな?)

現状、並列化されてしまっているもの

  • OSにぶらさがるプロセス
  • ネットワークを流れるパケット/フレームの処理
  • (なんらかのアプリケーションの)ユーザごとの処理
  • RDBMSとか
  • 駅の改札、お店のレジ、ATMにならんでいる人
  • 手際のいい人の調理
  • 人間の意識と無意識と不随筋の運動と神経と…
  • などなど

もう当たり前のように並列化されていますね。疑うまでもなく、並列化は効率化の基本公式なのでしょう。*2
ではなぜ今回わざわざ並列化を強調したかといえば、まだまだいろんなプログラム内部では並列化できる余地のある処理が残っている、「メニーコアの大喰らいに細いストローは不要だ!」という背景があるからでしょう。
並んでないものを並ばせる技術といいますか。細いを太くするというか、人生を濃くするというか。


ああ、人生が濃いってそういうことか。

どうでもいいけど

コアをふんだんに使う高速アプリが万が一暴走したらCPUくわれまくりで困りませんか?そういう意味ではシングルスレッディングなアプリは重要といえる(笑)。

*1:プロセスとスレッドの違いってなんでしょう。プロセスとは個々の間で共有する資源がなく 、スレッドは共有する資源があり密接なもののこと、というようにErlangのManualには書いてあったような気がします。

*2:熟達者ほど作業を並列化させています。一般的に人類について述べるならば、大人は作業を並列化させることができ、子供にはそれができません。ただ、大人の中でも並列化の上手下手はありますね。本当に上手な並列化のアイデアみたいなのは高速なアルゴリズムのアイデアと同じで皮一枚破らなければ思いつかないような気がします。