Jackson vs JSONIC、結果はJacksonの圧勝

2010/11/10追記 JSONIC 1.2.5 ベータ2で劇的に高速化されたとのことです。すばらしい!2010-11-10 - A.R.N [日記]


というつぶやきをしたところ、

とツッコミを受けたので訂正をします。APIレベルの話ではなくて内部処理レベルの話をしていたんですが、変なことを言って誤解を招いてスイマセン。言いたかった趣旨としては、単にJSONICだとシリアライズ対象のデータが巨大になった場合のパフォーマンスが非常に悪いという話です。

ということで、最近弊社で使い始めたJacksonとのベンチマークを掲載。

比較対象

ベンチマークコード

  • HashMap>をシリアライズしてFileOutputStreamに吐くだけのプログラムです。
  • JSON.encode()、ObjectMapper.writeValue()の部分にしか違いはありません。
JSONIC
    public static void main(String[] args) throws IOException {
        HashMap<String, Object> map = new HashMap<String, Object>();
        for (int i = 0; i < 1000; i++) {
            List<String> list = new ArrayList<String>();
            for (int j = 0; j < 1000; j++) {
                list.add("item" + j);
            }
            map.put("key" + i, list);
        }

        long t1 = System.nanoTime();
        FileOutputStream stream = new FileOutputStream("temp.txt");

        // - - - - - - - - - - - - - -
        JSON.encode(map, stream);
        // - - - - - - - - - - - - - -

        System.out.println(System.nanoTime() - t1);
    }
Jackson
    public static void main(String[] args) throws IOException {
        HashMap<String, Object> map = new HashMap<String, Object>();
        for (int i = 0; i < 1000; i++) {
            List<String> list = new ArrayList<String>();
            for (int j = 0; j < 1000; j++) {
                list.add("item" + j);
            }
            map.put("key" + i, list);
        }

        long t1 = System.nanoTime();
        FileOutputStream stream = new FileOutputStream("temp.txt");

        // - - - - - - - - - - - - - -
        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(stream, map);
        // - - - - - - - - - - - - - -

        System.out.println(System.nanoTime() - t1);
    }

結果

Jacksonの方が10倍以上速いです。Map1000×List1000とかJSONでやるなって話もなくはないんですが、弊社ではクライアント側で大量データ扱ってナンボみたいなところがあるので、結構重要だったりします。

Jackson JSONIC 速度比
Map1000×List1000 299.063 245 5527.890 932 1:18.4840198
Map1000×List10000 1348.112 466 99898.403 252 1:74.1024253
Map10000×List1000 1251.504 341 49485.444 934 1:39.5407697

単位はミリ秒、ナノ秒まで表記。

追記

型をつくってシリアライズしたときどうなるんだろーと思って、こんなのもテストしてみました。

    public static void main(String[] args) throws IOException {
//        HashMap<String, Person> data = new HashMap<String, Person>();
//        for (int i = 0; i < 100000; i++) {
//            data.put("item" + i, new Person("id"+i, "name"+i, i));
//        }

        ArrayList<Person> data = new ArrayList<Person>();
        for (int i = 0; i < 10000; i++) {
            data.add(new Person("id"+i, "name"+i, i));
        }

        long t1 = System.nanoTime();

        FileOutputStream stream = new FileOutputStream("temp.txt");
//        ObjectMapper mapper = new ObjectMapper();
//        mapper.writeValue(stream, data);
        JSON.encode(data, stream);

        System.out.println(System.nanoTime() - t1);
    }

    private static class Person {
        private String id;
        private String name;
        private int age;

        public Person(String id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }

        public int getAge() {
            return age;
        }

        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }
    }
Jackson JSONIC 速度比
Map100 238.047 490 60.364 634 1:0.253582317
Map1K 264.846 439 188.372 445 1:0.711251568
Map10K 380.608 350 979.267 174 1:2.57289987
Map100K 465.197 516 5526.531 864 1:11.8799686
List100 229.535 634 59.121 787 1:0.25757128
List1K 260.241 303 188.218 831 1:0.723247343
List10K 364.508 523 974.164 167 1:2.67254153
List100K 477.555 967 5320.503 284 1:11.1411094

Jacksonは要素数が増えても異常なほど遅くならない感じですね。