Scanner

ICFPを振り返るシリーズ1。2があるかは気にしない。

JavaのScannerが死ぬほど重かった。
正確には遅いらしいってのはどっかで聞いて知ってたんだけど、
ここまでとは、、、という感じ。

チーム内での可視化用ログのフォーマットが、

VIS [time] [name] [x] [y] [vx] [vy]

だったんですが、ほかのログも混ざるのでこれを行ごとに処理したかったわけです。
型は以下のソースからそんなもんか、という感じで。
さて、以下のテストを走らせて見る。

public class ScannerTest {
    public static void main(String[] args) {
        String str = "VIS 0 NAME 0.6 0.6 0.5 0.5";

        long t1 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; ++i) {
            Scanner s = new Scanner(str);
            String vis = s.next();
            int time = s.nextInt();
            String name = s.next();
            double x = s.nextDouble();
            double y = s.nextDouble();
            double vx = s.nextDouble();
            double vy = s.nextDouble();
        }
        long t2 = System.currentTimeMillis();
        System.out.println(t2 - t1);
    }
}
public class ScannerTest {
    public static void main(String[] args) {
        String str = "VIS 0 NAME 0.6 0.6 0.5 0.5";

        long t1 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; ++i) {
            StringTokenizer s = new StringTokenizer(str);
            String vis = s.nextToken();
            int time = Integer.parseInt(s.nextToken());
            String name = s.nextToken();
            double x = Double.parseDouble(s.nextToken());
            double y = Double.parseDouble(s.nextToken());
            double vx = Double.parseDouble(s.nextToken());
            double vy = Double.parseDouble(s.nextToken());
        }
        long t2 = System.currentTimeMillis();
        System.out.println(t2 - t1);
    }
}

結果。

$ java ScannerTest    # Scanner version
886565

$ java ScannerTest    # StringTokenizer version
2483

実に約400倍。そんなに遅かったとは。。。
ざっくりソースよんだところでは中で正規表現毎回かませてるのが遅い原因かな。
実行環境。PenM 1.7G, java 1.6 update 13, w/ cygwin console.