著作一覧 |
ブラウザをマウスでくりくりやったりたまにぽつぽつ文字を入れるようなのはどうでも良くて、たとえばATMあたりを考えてみたくなるわけだ。
最初のページはボタンを押して入金か出金か振込か残高照会かを選ばせる。と同時にカードを入れるのもOK。
ここで、各ボタンクリックに対してFutureを割り当ててコンプリート時の処理を記述するとするじゃん。もちろん、カードの挿入による磁気ストライプの読み込みイベントについても同様とする。
で、一見するとおそらく非常にきれいに書けるのは間違いないのだが、そこに間違いのもとがある。
ボタンを押す前に磁気ストライプを読み込んだら、自動的に引き落としページへ遷移するとして、各ボタンも同様に各ページに遷移するとする。
ここで、ページ遷移にIO(あるいはHTTPのようにサーバとの通信)が発生して、そこも当然、非同期な書き方をするとする。つまり、遷移要求のFutureを作ってコンプリートしたらそのページの処理をするというような書き方だ。
で、もちろん、こんなナイーブな実装をしてはだめだ。
というのは、ページ遷移の間に、別のボタンを押されたらナイーブな実装であれば、そのページへの遷移を呼び出すことになり、いずれか先に返ったページの処理をしようとしてまた非同期要求をした時点で、もう一方のページが返って来て、とやっているうちに、あせって挿入されたカードの磁気ストライプ読み込みコンプリートの処理が起動されて、つまり、死ぬ。
ということは、いずれか最初にコンプリートされた時点で、他の非同期要求をすべてキャンセルして回らなければならず、ページ遷移のような非同期要求中は他の非同期要求のコンプリートを無視しなければならず(でも磁気ストライプ読み込みについては遷移先でいずれにしても必要なのであれば、バッファしておく必要があり、しかしマシンのメモリにバッファしていればしているほど危険が危ないので何らかの工夫が必要となり……とやっているうちに、非同期プログラミングって何の役に立つのだ? と当然の疑問が湧いて来ることになる。
なんと今から25年も前にWindows3のイベントドリブンプログラミングの時にぶち当たった問題の再現だ。そりゃ、C++のコールバックベースのイベントドリブンプログラミングよりははるかに記述はしやすくなっていはいるが、本質的な難しさは何も変わってはいない。
ジェズイットを見習え |
一般的にconcurrencyって枝分かれさせる方はtrivialで、分かれたのをまとめる方が難しいんですよね。なんかプロセス代数あたりでちゃんとやってたような気がするのですが。