非同期リクエスト-レスポンスパターンについて考える
非同期I/Oとかスレッドとかの話。
なんかのはずみで「Java並行処理プログラミング」を読んでた。そして、この本はなんかのはずみで鞄の中で肉汁を浴びてたので、ちょっと色が付いてる。
いや、肉汁はどうでもよいのだけど、半分くらい読んでて、それなりにおもしろい。前半が一般的な並列の話題、後半が応用とかJavaのライブラリの話とか。
現在のJavaでは、自分でスレッド作ったり、消したりする、というようなのはもはや前時代的…かどうかは状況によると思うけど、とにかく、スレッドプールがあって、タスクごとにスレッドを割り当てる…みたいなありがちパターンでは、自分でスレッド管理したりせずに、Executorフレームワークというのを使うらしい。
↓こんな感じに書ける。
import java.util.concurrent.*; class Nanika implements Callable<Integer> { private final int v; Nanika( int v ) { this.v = v; } public Integer call( ) throws InterruptedException { for ( int i=0; i<10; i++ ) { System.out.println( v + " : " + i ); Thread.sleep( 1000 ); } return v; } }; class Main { public static void main( String args[] ) { ExecutorService ex = Executors.newFixedThreadPool( 20 ); try { java.util.Vector<Future<Integer>> futures = new java.util.Vector<Future<Integer>>(3); for ( int i=0; i<3; i++ ) { Future<Integer> f = ex.submit( new Nanika(i) ); futures.add( f ); } for ( int i=0; i<3; i++ ) { System.out.println( futures.get(i).get() ); } ex.shutdown(); } catch ( InterruptedException e ) { } catch ( ExecutionException e ) { } } }
これが、↓こんなん
0 : 0 1 : 0 2 : 0 0 : 1 2 : 1 1 : 1 0 : 2 (....) 0 : 9 1 : 9 2 : 9 0 1 2
いや、こんなサンプルだけあってもなんの参考にもならないと思うけど。スレッドプールのポリシーと、タスクの依頼、タスク完了後のレスポンス取得、が、ちゃんと分離されてる。
詳細の説明はまあ、どっかで読んでもらうとして、Futureパターンというのが「へー」、と思った。
for ( int i=0; i<3; i++ ) { Future<Integer> f = ex.submit( new Nanika(i) ); futures.add( f );
このへんの部分。Executorというのが、スレッドプール。んで、exがオブジェクトで、submitで、スレッドプールに、タスクの実行を依頼する。(実際にいつ実行するかはスレッドプールのポリシーによる)
そんで、依頼すると、Futureというオブジェクトが返ってくる。まあ、それがうんにゃうんにゃ(説明になってない)
submitした時点ではブロックしないで、Futureが返ってくるだけ。んで、Futureのgetを呼んで、値を拾おうとしたときにブロックする。
上のコードだと、ブロックしてるのは、↓このへん
for ( int i=0; i<3; i++ ) { System.out.println( futures.get(i).get() ); // このgetでブロックする。 }
まあ、そんなこんな。「値を生成するタスクを実行中ですよー」という概念がFutureというオブジェクトになってる。
で、それをC++で書くとどうなるかなー、とか妄想してたんだけど、なんか、このパターンって、昔なんか考えたなー、とか思って、多分非同期I/Oについて3日ぐらい考えたときに似たようなパターンだったような気がしたのだった。
非同期I/Oと、別スレッドに処理を依頼する、というのは似たようなインターフェース(よく考えれば当たり前なのだけど)で、
- リクエストを投げる
- こっちとあっちで別々の処理をする
- あっちの処理が終わるまで待機
- レスポンスをもらう
こういう流れが似てる。で、あと、
- ブロックしてるのを割り込んでキャンセルする
というインターフェースが同じ。
ここらへんをうまくなんとかして、「リクエスト→レスポンスパターンのライブラリ」ができれば、ただのスレッドのラッパー以上のライブラリができるのじゃないかなー。と、考えたのだった。
飽きるまで続く。