Biorę na tapetę według mnie najlepsze serializatory  w javie:

Serializuję dwa obiekty zawierające stringa (1470 bytes) i Double.MAX_VALUE

Wyniki benchmarku:

Benchmark                       Mode  Cnt    Score    Error   Units
SerializeBenchmark.fst         thrpt    5    0,477 ±  0,039  ops/ms
SerializeBenchmark.google      thrpt    5  910,106 ± 60,102  ops/ms
SerializeBenchmark.jackson     thrpt    5   66,483 ± 12,103  ops/ms
SerializeBenchmark.kryo        thrpt    5   92,880 ± 27,383  ops/ms
SerializeBenchmark.protostuff  thrpt    5  187,986 ± 12,292  ops/ms

A teraz puścimy to w 5 wątkach:

Benchmark                       Mode  Cnt     Score      Error   Units
SerializeBenchmark.fst         thrpt    5     2,111 ±    0,804  ops/ms
SerializeBenchmark.google      thrpt    5   971,071 ±   63,001  ops/ms
SerializeBenchmark.jackson     thrpt    5   252,071 ±   16,351  ops/ms
SerializeBenchmark.kryo        thrpt    5   232,511 ±   87,517  ops/ms
SerializeBenchmark.protostuff  thrpt    5  7483,938 ± 1240,685  ops/ms

A teraz 50 wątków 🙂

Benchmark                       Mode  Cnt     Score     Error   Units
SerializeBenchmark.fst         thrpt    5     1,897 ±   0,292  ops/ms
SerializeBenchmark.google      thrpt    5   959,975 ± 107,916  ops/ms
SerializeBenchmark.jackson     thrpt    5   261,513 ±  13,936  ops/ms
SerializeBenchmark.kryo        thrpt    5   308,221 ±  37,969  ops/ms
SerializeBenchmark.protostuff  thrpt    5  7742,153 ± 121,602  ops/ms

Jak widać na wynikach, puszczając serializację w jednym wątku Google Protobuf radzi sobie najlepiej natomiast ilość wątków w żaden sposób nie przyspiesza jago działania czego nie można powiedzieć o Protostuff.io gdzie wzrost był diametralny.

Zmniejszanie wielkości stringa do 59 bytes przełożyło się na szybkość wykonywania się Google Protobuf i Kryo:

Benchmark                       Mode  Cnt     Score     Error   Units
SerializeBenchmark.fst         thrpt    5     1,941 ±   0,351  ops/ms
SerializeBenchmark.google      thrpt    5  8555,033 ± 488,605  ops/ms
SerializeBenchmark.jackson     thrpt    5   644,608 ±  33,522  ops/ms
SerializeBenchmark.kryo        thrpt    5  4497,039 ± 194,688  ops/ms
SerializeBenchmark.protostuff  thrpt    5  7271,828 ± 471,228  ops/ms

Jeszcze wyniki z SampleTime:

Result "fst":
  N = 10545
  mean =  23674,701 ±(99.9%) 589,445 us/op

  Histogram, us/op:
    [     0,000,  12500,000) = 3261 
    [ 12500,000,  25000,000) = 2955 
    [ 25000,000,  37500,000) = 2231 
    [ 37500,000,  50000,000) = 1238 
    [ 50000,000,  62500,000) = 487 
    [ 62500,000,  75000,000) = 217 
    [ 75000,000,  87500,000) = 81 
    [ 87500,000, 100000,000) = 40 
    [100000,000, 112500,000) = 24 
    [112500,000, 125000,000) = 5 
    [125000,000, 137500,000) = 4 
    [137500,000, 150000,000) = 1 
    [150000,000, 162500,000) = 1 
    [162500,000, 175000,000) = 0 
    [175000,000, 187500,000) = 0 

  Percentiles, us/op:
      p(0,0000) =   1689,600 us/op
     p(50,0000) =  20938,752 us/op
     p(90,0000) =  47448,064 us/op
     p(95,0000) =  57389,875 us/op
     p(99,0000) =  82646,139 us/op
     p(99,9000) = 114866,520 us/op
     p(99,9900) = 153048,370 us/op
     p(99,9990) = 153878,528 us/op
     p(99,9999) = 153878,528 us/op
    p(100,0000) = 153878,528 us/op
Result "google":
  N = 2502277
  mean =     51,858 ±(99.9%) 4,069 us/op

  Histogram, us/op:
    [     0,000,  25000,000) = 2500907 
    [ 25000,000,  50000,000) = 471 
    [ 50000,000,  75000,000) = 299 
    [ 75000,000, 100000,000) = 268 
    [100000,000, 125000,000) = 174 
    [125000,000, 150000,000) = 114 
    [150000,000, 175000,000) = 35 
    [175000,000, 200000,000) = 7 
    [200000,000, 225000,000) = 2 
    [225000,000, 250000,000) = 0 
    [250000,000, 275000,000) = 0 

  Percentiles, us/op:
      p(0,0000) =      0,585 us/op
     p(50,0000) =      6,448 us/op
     p(90,0000) =      8,352 us/op
     p(95,0000) =      9,072 us/op
     p(99,0000) =     13,136 us/op
     p(99,9000) =   1653,645 us/op
     p(99,9900) = 110171,836 us/op
     p(99,9990) = 164072,286 us/op
     p(99,9999) = 202751,066 us/op
    p(100,0000) = 215482,368 us/op
Result "jackson":
  N = 1327485
  mean =    189,506 ±(99.9%) 10,396 us/op

  Histogram, us/op:
    [     0,000,  25000,000) = 1324594 
    [ 25000,000,  50000,000) = 881 
    [ 50000,000,  75000,000) = 965 
    [ 75000,000, 100000,000) = 600 
    [100000,000, 125000,000) = 266 
    [125000,000, 150000,000) = 100 
    [150000,000, 175000,000) = 30 
    [175000,000, 200000,000) = 19 
    [200000,000, 225000,000) = 20 
    [225000,000, 250000,000) = 7 
    [250000,000, 275000,000) = 3 

  Percentiles, us/op:
      p(0,0000) =     12,944 us/op
     p(50,0000) =     27,168 us/op
     p(90,0000) =     29,600 us/op
     p(95,0000) =     30,976 us/op
     p(99,0000) =     37,952 us/op
     p(99,9000) =  66225,046 us/op
     p(99,9900) = 134283,631 us/op
     p(99,9990) = 214886,027 us/op
     p(99,9999) = 260584,932 us/op
    p(100,0000) = 261357,568 us/op
Result "kryo":
  N = 1469072
  mean =    167,398 ±(99.9%) 9,844 us/op

  Histogram, us/op:
    [     0,000,  25000,000) = 1466513 
    [ 25000,000,  50000,000) = 723 
    [ 50000,000,  75000,000) = 772 
    [ 75000,000, 100000,000) = 505 
    [100000,000, 125000,000) = 275 
    [125000,000, 150000,000) = 117 
    [150000,000, 175000,000) = 74 
    [175000,000, 200000,000) = 53 
    [200000,000, 225000,000) = 27 
    [225000,000, 250000,000) = 11 
    [250000,000, 275000,000) = 2 

  Percentiles, us/op:
      p(0,0000) =     10,736 us/op
     p(50,0000) =     23,520 us/op
     p(90,0000) =     26,368 us/op
     p(95,0000) =     27,616 us/op
     p(99,0000) =     32,960 us/op
     p(99,9000) =  60555,264 us/op
     p(99,9900) = 157024,256 us/op
     p(99,9990) = 222441,334 us/op
     p(99,9999) = 264054,662 us/op
    p(100,0000) = 273154,048 us/op
Result "protostuff":
  N = 2535291
  mean =      7,083 ±(99.9%) 1,455 us/op

  Histogram, us/op:
    [     0,000,  25000,000) = 2535095 
    [ 25000,000,  50000,000) = 57 
    [ 50000,000,  75000,000) = 61 
    [ 75000,000, 100000,000) = 42 
    [100000,000, 125000,000) = 19 
    [125000,000, 150000,000) = 11 
    [150000,000, 175000,000) = 4 
    [175000,000, 200000,000) = 1 
    [200000,000, 225000,000) = 1 
    [225000,000, 250000,000) = 0 
    [250000,000, 275000,000) = 0 

  Percentiles, us/op:
      p(0,0000) =      0,004 us/op
     p(50,0000) =      0,831 us/op
     p(90,0000) =      1,468 us/op
     p(95,0000) =      1,684 us/op
     p(99,0000) =      2,212 us/op
     p(99,9000) =      6,230 us/op
     p(99,9900) =  10534,912 us/op
     p(99,9990) = 109360,353 us/op
     p(99,9999) = 172171,596 us/op
    p(100,0000) = 204210,176 us/op
Benchmark                        Mode      Cnt      Score     Error  Units
SerializeBenchmark.fst         sample    10545  23674,701 ± 589,445  us/op
SerializeBenchmark.google      sample  2502277     51,858 ±   4,069  us/op
SerializeBenchmark.jackson     sample  1327485    189,506 ±  10,396  us/op
SerializeBenchmark.kryo        sample  1469072    167,398 ±   9,844  us/op
SerializeBenchmark.protostuff  sample  2535291      7,083 ±   1,455  us/op

Wnioskują, jedynymi godnymi rozważania serializatorami są google i protostuff natomiast google serializator wymaga wygenerowania klas na podstawie schematu opracowanego w pliku .proto a w przypadku protostuff wykorzystujemy RuntimeSchema gdzie nie musimy się zastanawiać nad nowo dodanymi polami w klasie.

Benchmarki wykonane za pomocą OpenJDK JMH z parametrami: -XX:+UseG1GC -Xms1g -Xmx1g

Przykładowe kawłki kodu:

Fast serializer:

public void fst () {
    OnHeapCoder coder = new OnHeapCoder(false, StandardObject.class);
    byte barray[] = coder.toByteArray(standardObject);
    standardObject = (StandardObject) coder.toObject(barray);
}

Google:

public void google () {
    byte[] barray = googleObject.toByteArray();
    try {
        googleObject = ObiektOuterClass.Obiekt.parseFrom(barray);
    } catch (InvalidProtocolBufferException e) {
        e.printStackTrace();
    }
}

Jackson:

public void jackson() throws Exception {
    String string = mapper.writeValueAsString(standardObject);
    StandardObject result = mapper.readValue(string, StandardObject.class);
}

Kryo:

public void kryo () {
    Output output = new Output(5, 5000);
    kryo.writeObject(output, standardObject);
    byte[] bytes = output.toBytes();
    output.clear();
    Input input = new Input(bytes);
    standardObject = kryo.readObject(input, StandardObject.class);
}

Protostaff:

public void protostuff () {
    byte[] barray = ProtostuffIOUtil.toByteArray(standardObject, schema, LinkedBuffer.allocate());
    standardObject = new StandardObject();
    ProtostuffIOUtil.mergeFrom(barray, standardObject, schema);
}

Obiekt serializowany (dla google analogiczny ale wygenerowany):

public class StandardObject implements Serializable {

    @Tag(value = 1, alias = "v")
    private double val;
    @Tag(value = 2, alias = "o")
    private StandardObject standardObject;
    @Tag(value = 3, alias = "s")
    private String string;

    public StandardObject getStandardObject() {
        return standardObject;
    }

    public void setStandardObject(StandardObject standardObject) {
        this.standardObject = standardObject;
    }

    public double getVal() {
        return val;
    }

    public void setVal(double val) {
        this.val = val;
    }

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        StandardObject that = (StandardObject) o;
        return Double.compare(that.val, val) == 0 &&
                Objects.equals(standardObject, that.standardObject) &&
                Objects.equals(string, that.string);
    }

    @Override
    public int hashCode() {
        return Objects.hash(val, standardObject, string);
    }

    @Override
    public String toString() {
        return "StandardObject{" +
                "val=" + val +
                ", standardObject=" + standardObject +
                '}';
    }

}

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *