非同期リクエスト-レスポンスパターンについて考える

非同期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と、別スレッドに処理を依頼する、というのは似たようなインターフェース(よく考えれば当たり前なのだけど)で、

  1. リクエストを投げる
  2. こっちとあっちで別々の処理をする
  3. あっちの処理が終わるまで待機
  4. レスポンスをもらう

こういう流れが似てる。で、あと、

  • ブロックしてるのを割り込んでキャンセルする

というインターフェースが同じ。


ここらへんをうまくなんとかして、「リクエスト→レスポンスパターンのライブラリ」ができれば、ただのスレッドのラッパー以上のライブラリができるのじゃないかなー。と、考えたのだった。
飽きるまで続く。