覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Gson vs Genson vs Fastjson (2)

以下記事に続いて、Gson, Genson, Fastjson, JSONIC のベンチマークをJMHを用いて取得しました。

JSONの項目数が1, 2, 4, 8個の場合のそれぞれについて以下操作を実施して測定してみました

  • Javaオブジェクト⇒JSON文字列の変換(Serialize)
  • JSON文字列⇒Javaオブジェクトの変換(Deserialize)

pom.xmlに追加した内容は以下の通りです
(Lombokの@Dataアノテーションを利用してコード省略をするため、Lombokのライブラリも組み込んでいます)

<dependency>
  <groupId>com.owlike</groupId>
  <artifactId>genson</artifactId>
   <version>1.4</version>
</dependency>
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.7</version>
</dependency>
<dependency>
  <groupId>net.arnx</groupId>
  <artifactId>jsonic</artifactId>
  <version>1.3.10</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.17</version>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.16.10</version>
  <scope>provided</scope>
</dependency>

■変換対象のJavaオブジェクト

  • メンバが1個
import lombok.Data;

@Data
public class Param1 {

    /**
     * JSON文字列
     *
     * {
     *   "data1": "abcde"
     * }
     */
    public static final String JSON_STR = "{\"data1\":\"abcde\"}";

    public static final Param1 INSTANCE = new Param1();

    static {
        INSTANCE.setData1("012345");
    }

    private String data1;
}
  • メンバが2個
import lombok.Data;

@Data
public class Param2 {

    /**
     * JSON文字列
     * 
     * {
     *   "data1": "abcde",
     *   "data2": "fghij"
     * }
     */
    public static final String JSON_STR = "{\"data1\":\"abcde\", \"data2\":\"fghij\"}";

    public static final Param2 INSTANCE = new Param2();

    static {
        INSTANCE.setData1("12345");
        INSTANCE.setData2("67890");
    }

    private String data1;

    private String data2;
}
  • メンバが4個
import lombok.Data;

@Data
public class Param4 {

    /**
     * JSON文字列
     *
     * {
     *   "data1": "abcde",
     *   "data2": "fghij",
     *   "data3": "klmno",
     *   "data4": "pqrst"
     * }
     */
    public static final String JSON_STR =
            "{\"data1\":\"abcde\", \"data2\":\"fghij\", \"data3\":\"klmno\", \"data4\":\"pqrst\"}";

    public static final Param4 INSTANCE = new Param4();

    static {
        INSTANCE.setData1("12345");
        INSTANCE.setData2("67890");
        INSTANCE.setData3("54321");
        INSTANCE.setData4("09876");
    }

    private String data1;

    private String data2;

    private String data3;

    private String data4;
}
  • メンバが8個
import lombok.Data;

@Data
public class Param8 {

    /**
     * JSON文字列
     *
     * {
     *   "data1": "abcde",
     *   "data2": "fghij",
     *   "data3": "klmno",
     *   "data4": "pqrst",
     *   "data5": "0bcde",
     *   "data6": "1ghij",
     *   "data7": "2lmno",
     *   "data8": "3qrst"
     * }
     */
    public static final String JSON_STR =
            "{\"data1\":\"abcde\", \"data2\":\"fghij\", \"data3\":\"klmno\", \"data4\":\"pqrst\", \"data5\":\"0bcde\", \"data6\":\"1ghij\", \"data7\":\"2lmno\", \"data8\":\"3qrst\"}";

    public static final Param8 INSTANCE = new Param8();

    static {
        INSTANCE.setData1("12345");
        INSTANCE.setData2("67890");
        INSTANCE.setData3("54321");
        INSTANCE.setData4("09876");
        INSTANCE.setData5("12344");
        INSTANCE.setData6("67899");
        INSTANCE.setData7("44321");
        INSTANCE.setData8("99876");
    }

    private String data1;

    private String data2;

    private String data3;

    private String data4;

    private String data5;

    private String data6;

    private String data7;

    private String data8;
}

■ベンチマーク取得用のコード

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import com.google.gson.Gson;
import com.owlike.genson.Genson;

public class JsonBenchmark {

    static final Genson genson = new Genson();

    static final Gson gson = new Gson();

    @Benchmark
    public void Gson_Param1_Deserialize() {
        Param1 obj = gson.fromJson(Param1.JSON_STR, Param1.class);
    }

    @Benchmark
    public void Genson_Param1_Deserialize() {
        Param1 obj = genson.deserialize(Param1.JSON_STR, Param1.class);
    }

    @Benchmark
    public void JSONIC_Param1_Deserialize() {
        Param1 obj = net.arnx.jsonic.JSON.decode(Param1.JSON_STR, Param1.class);
    }

    @Benchmark
    public void FastJson_Param1_Deserialize() {
        Param1 obj = com.alibaba.fastjson.JSON.parseObject(Param1.JSON_STR, Param1.class);
    }

    @Benchmark
    public void Gson_Param1_Serialize() {
        String json = gson.toJson(Param1.INSTANCE);
    }

    @Benchmark
    public void Genson_Param1_Serialize() {
        String json = genson.serialize(Param1.INSTANCE);
    }

    @Benchmark
    public void JSONIC_Param1_Serialize() {
        String json = net.arnx.jsonic.JSON.encode(Param1.INSTANCE);
    }

    @Benchmark
    public void FastJson_Param1_Serialize() {
        String json = com.alibaba.fastjson.JSON.toJSONString(Param1.INSTANCE);
    }

    /* --------------------------------------------------------------------- */

    @Benchmark
    public void Gson_Param2_Deserialize() {
        Param2 obj = gson.fromJson(Param2.JSON_STR, Param2.class);
    }

    @Benchmark
    public void Genson_Param2_Deserialize() {
        Param2 obj = genson.deserialize(Param2.JSON_STR, Param2.class);
    }

    @Benchmark
    public void JSONIC_Param2_Deserialize() {
        Param2 obj = net.arnx.jsonic.JSON.decode(Param2.JSON_STR, Param2.class);
    }

    @Benchmark
    public void FastJson_Param2_Deserialize() {
        Param2 obj = com.alibaba.fastjson.JSON.parseObject(Param2.JSON_STR, Param2.class);
    }

    @Benchmark
    public void Gson_Param2_Serialize() {
        String json = gson.toJson(Param2.INSTANCE);
    }

    @Benchmark
    public void Genson_Param2_Serialize() {
        String json = genson.serialize(Param2.INSTANCE);
    }

    @Benchmark
    public void JSONIC_Param2_Serialize() {
        String json = net.arnx.jsonic.JSON.encode(Param2.INSTANCE);
    }

    @Benchmark
    public void FastJson_Param2_Serialize() {
        String json = com.alibaba.fastjson.JSON.toJSONString(Param2.INSTANCE);
    }

    /* --------------------------------------------------------------------- */


    @Benchmark
    public void Gson_Param4_Deserialize() {
        Param4 obj = gson.fromJson(Param4.JSON_STR, Param4.class);
    }

    @Benchmark
    public void Genson_Param4_Deserialize() {
        Param4 obj = genson.deserialize(Param4.JSON_STR, Param4.class);
    }

    @Benchmark
    public void JSONIC_Param4_Deserialize() {
        Param4 obj = net.arnx.jsonic.JSON.decode(Param4.JSON_STR, Param4.class);
    }

    @Benchmark
    public void FastJson_Param4_Deserialize() {
        Param4 obj = com.alibaba.fastjson.JSON.parseObject(Param4.JSON_STR, Param4.class);
    }

    @Benchmark
    public void Gson_Param4_Serialize() {
        String json = gson.toJson(Param4.INSTANCE);
    }

    @Benchmark
    public void Genson_Param4_Serialize() {
        String json = genson.serialize(Param4.INSTANCE);
    }

    @Benchmark
    public void JSONIC_Param4_Serialize() {
        String json = net.arnx.jsonic.JSON.encode(Param4.INSTANCE);
    }

    @Benchmark
    public void FastJson_Param4_Serialize() {
        String json = com.alibaba.fastjson.JSON.toJSONString(Param4.INSTANCE);
    }

    /* --------------------------------------------------------------------- */


    @Benchmark
    public void Gson_Param8_Deserialize() {
        Param8 obj = gson.fromJson(Param8.JSON_STR, Param8.class);
    }

    @Benchmark
    public void Genson_Param8_Deserialize() {
        Param8 obj = genson.deserialize(Param8.JSON_STR, Param8.class);
    }

    @Benchmark
    public void JSONIC_Param8_Deserialize() {
        Param8 obj = net.arnx.jsonic.JSON.decode(Param8.JSON_STR, Param8.class);
    }

    @Benchmark
    public void FastJson_Param8_Deserialize() {
        Param8 obj = com.alibaba.fastjson.JSON.parseObject(Param8.JSON_STR, Param8.class);
    }

    @Benchmark
    public void Gson_Param8_Serialize() {
        String json = gson.toJson(Param8.INSTANCE);
    }

    @Benchmark
    public void Genson_Param8_Serialize() {
        String json = genson.serialize(Param8.INSTANCE);
    }

    @Benchmark
    public void JSONIC_Param8_Serialize() {
        String json = net.arnx.jsonic.JSON.encode(Param8.INSTANCE);
    }

    @Benchmark
    public void FastJson_Param8_Serialize() {
        String json = com.alibaba.fastjson.JSON.toJSONString(Param8.INSTANCE);
    }

    /* --------------------------------------------------------------------- */

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                 .include(JsonBenchmark.class.getSimpleName())
                .warmupIterations(15)
                .forks(1)
                .mode(Mode.Throughput)
                .build();
        new Runner(opt).run();
    }

}

■実行結果

Benchmark                                   Mode  Cnt        Score        Error  Units
JsonBenchmark.FastJson_Param1_Deserialize  thrpt   20  4195673.493 ±  19574.347  ops/s
JsonBenchmark.FastJson_Param1_Serialize    thrpt   20  3449799.211 ±  33319.993  ops/s
JsonBenchmark.FastJson_Param2_Deserialize  thrpt   20  1321092.272 ±  10055.516  ops/s
JsonBenchmark.FastJson_Param2_Serialize    thrpt   20  2472298.598 ± 249420.632  ops/s
JsonBenchmark.FastJson_Param4_Deserialize  thrpt   20   589985.238 ±  31710.681  ops/s
JsonBenchmark.FastJson_Param4_Serialize    thrpt   20  1756121.681 ±  37347.932  ops/s
JsonBenchmark.FastJson_Param8_Deserialize  thrpt   20   295910.818 ±   3115.337  ops/s
JsonBenchmark.FastJson_Param8_Serialize    thrpt   20  1121379.655 ±  19931.463  ops/s
JsonBenchmark.Genson_Param1_Deserialize    thrpt   20   472028.167 ±  43954.179  ops/s
JsonBenchmark.Genson_Param1_Serialize      thrpt   20   789158.670 ±  14181.205  ops/s
JsonBenchmark.Genson_Param2_Deserialize    thrpt   20   449204.789 ±  14293.770  ops/s
JsonBenchmark.Genson_Param2_Serialize      thrpt   20   679484.606 ±  37354.086  ops/s
JsonBenchmark.Genson_Param4_Deserialize    thrpt   20   305384.858 ±  30222.529  ops/s
JsonBenchmark.Genson_Param4_Serialize      thrpt   20   515371.617 ±  27980.245  ops/s
JsonBenchmark.Genson_Param8_Deserialize    thrpt   20   245868.402 ±  24096.430  ops/s
JsonBenchmark.Genson_Param8_Serialize      thrpt   20   350953.967 ±  25198.046  ops/s
JsonBenchmark.Gson_Param1_Deserialize      thrpt   20   618404.934 ±  40876.569  ops/s
JsonBenchmark.Gson_Param1_Serialize        thrpt   20  1295734.021 ±  65292.606  ops/s
JsonBenchmark.Gson_Param2_Deserialize      thrpt   20   415526.341 ±  46925.218  ops/s
JsonBenchmark.Gson_Param2_Serialize        thrpt   20   896601.209 ±   8078.346  ops/s
JsonBenchmark.Gson_Param4_Deserialize      thrpt   20   356610.773 ±  27809.496  ops/s
JsonBenchmark.Gson_Param4_Serialize        thrpt   20   523139.719 ±   3893.311  ops/s
JsonBenchmark.Gson_Param8_Deserialize      thrpt   20   231396.047 ±   7577.424  ops/s
JsonBenchmark.Gson_Param8_Serialize        thrpt   20   270730.003 ±   4979.947  ops/s
JsonBenchmark.JSONIC_Param1_Deserialize    thrpt   20    78736.888 ±   2090.946  ops/s
JsonBenchmark.JSONIC_Param1_Serialize      thrpt   20   125495.921 ±  12245.697  ops/s
JsonBenchmark.JSONIC_Param2_Deserialize    thrpt   20    73901.511 ±   1970.644  ops/s
JsonBenchmark.JSONIC_Param2_Serialize      thrpt   20   126911.843 ±    740.589  ops/s
JsonBenchmark.JSONIC_Param4_Deserialize    thrpt   20    65997.762 ±    696.490  ops/s
JsonBenchmark.JSONIC_Param4_Serialize      thrpt   20   107243.447 ±    793.303  ops/s
JsonBenchmark.JSONIC_Param8_Deserialize    thrpt   20    48507.646 ±   2978.033  ops/s
JsonBenchmark.JSONIC_Param8_Serialize      thrpt   20    88963.475 ±    755.584  ops/s


Scoreの値を表にまとめてみました。

Serialize/Deserialize ライブラリ 項目1個 項目2個 項目4個 項目8個
Bean⇒JSON (Serialize) Fastjson 3449799.211 2472298.598 1756121.681 1121379.655
Genson 789158.670 679484.606 515371.617 350953.967
Gson 1295734.021 896601.209 523139.719 270730.003
JSONIC 125495.921 126911.843 107243.447 88963.475
JSON⇒Bean (Deserialize) Fastjson 4195673.493 1321092.272 589985.238 295910.818
Genson 472028.167 449204.789 305384.858 245868.402
Gson 618404.934 415526.341 356610.773 231396.047
JSONIC 78736.888 73901.511 65997.762 48507.646

JSONの項目数で比較してみると、基本的に項目数が増えるごとにScoreが減少していてそれだけ時間を要することが分かります。
ライブラリごとの結果を比較してみると、JSONICの遅さとFastjsonの速さが目につきます。
項目8個の場合のDeserializeでは、Fastjson, Genson, Gsonでの性能差はあまり無いという結果になっています。



関連エントリ