kilim で Java でもジェネレーター

2008/06/27 3:41am

TwitterErlang をきっかけに注目を集めるようになった軽量プロセス(とかマイクロスレッドとか)を Java で実現するためのライブラリに kilim があります。

夜中に突然 Java が書きたくなって、まだ、Examples を動かしてみた程度ですが、とりあえず Python のジェネレーターっぽいことができるのは分かったので記事にしておきます。暇と知識が増えたら、もうすこし突っ込んだ記事もあげる予定です(自信がないので今回、ですます調)。

ジェネレーターの例

では、本当につまらない例です。フィボナッチ数を求めるプログラムをどうぞ。

import kilim.Generator;
import kilim.pausable;

public class Fib extends Generator<Integer> {

  public @pausable void execute() {  // (1)
    int fib1 = 0;
    int fib2 = 1;

    while (true) {
      yield(fib1);  // (2)
      fib2 = fib1 + fib2;
      fib1 = fib2 - fib1;
    }
  }

  public static void main(String[] args) {
    final Fib fib = new Fib();

    for (int i = 0; i <= 10; i++) {
      System.out.printf("Fib(%d) = %d\n", i, fib.next()); // (3)
    }
  }

}

面白い箇所の行にコメントで番号を振りました。

  1. 協調動作させたいメソッドは、このように @pausable アノテーションで指示します
  2. 呼び出し側に制御を戻すときは yield メソッドを使います。Python 的
  3. kilim.Generatorjava.util.Iteratorjava.lang.Iterable インターフェースを実装しているので、こんなふうに使います。ますます Python

ビルドと実行方法

上記のソースコードを実行するまでの手順をまとめておきます。

まずは公式サイトからソースコードをダウンロードして展開、ビルドします。

% tar xvzf kilim-0.5.tgz.tar
% cd kilim-0.5
% ant

.jar も作っておきましょう(2008/6/27追記cd classes が抜けていたので追記しました)。

% cd classes/
% jar cvf kilim-0.5.jar kilim

適当なディレクトリを作成して、さきほど作成した kilim-0.5.jar とソースコードに含まれている asm-all-2.2.3.jar をコピーします。また、上記のサンプルプログラムを Fib.java という名前で、同じディレクトリに保存してください。

早速、Fib.java をコンパイルします。

% javac -cp ./kilim-0.5.jar ./Fib.java
% ls
Fib.class               Fib.java                asm-all-2.2.3.jar       kilim-0.5.jar

Fib.class が作成されているのでコンパイルは成功しています。実行してみましょう。

% java -cp .:./kilim-0.5.jar Fib
############################################################
Task class Fib has either not been woven or the classpath is incorrect
############################################################
java.lang.Exception: Stack trace
        at java.lang.Thread.dumpStack(Thread.java:1176)
        at kilim.Task.errNotWoven(Task.java:188)
        at kilim.Task.execute(Task.java:252)
        at kilim.Task._runExecute(Task.java:291)
        at kilim.Generator.next(Generator.java:47)
        at Fib.main(Fib.java:22)

あらら … 不可解なエラーが出てしまいました。

種を明かすと kilim はバイトコード改変を利用しています。そのため、実行する前に、対象の .class ファイルを kilim.tools.Weaver で変換してやらないといけません(ソースコードのコメントを読むと、継続渡し形式(CPS)変換をしているらしい)。

% java -cp .:./kilim-0.5.jar:./asm-all-2.2.3.jar kilim.tools.Weaver -d . Fib
Wrote: ./kilim/S_I2.class
Wrote: ./Fib.class

なんだか .class が増えちゃったけど、いまのところ気にしない…

% java -cp .:./kilim-0.5.jar Fib
Fib(0) = 0
Fib(1) = 1
Fib(2) = 1
Fib(3) = 2
Fib(4) = 3
Fib(5) = 5
Fib(6) = 8
Fib(7) = 13
Fib(8) = 21
Fib(9) = 34
Fib(10) = 55

今度は実行できました。フィボナッチ数が順番に出力されているのが分かると思います。