デシリアライズを最適化するための最良の方法は何ですか?
私は現在、いくつかの複雑なオブジェクトのシリアル化と逆シリアル化に標準のGson.toJsonメソッドとGson.fromJsonメソッドを使用しており、可能であれば逆シリアル化時間を短縮したいと考えています。
私のオブジェクトの中で最も複雑なものには、それが重要な場合は43個の変数が含まれています。
Gsonを使用し、別のJava to / from-JSON APIに切り替えたくない場合、およびGsonのautomagicデータバインディングのパフォーマンスが十分でない場合は、Gson APIを使用したままにして、いくつかを絞り出すことができます。適度に優れたパフォーマンス。
https://github.com/eishay/jvm-serializers/wikiに投稿された最新のパフォーマンステストの結果は、ストリーミングを使用することで、Gsonのシリアル化と逆シリアル化の合計パフォーマンスが約25%向上する可能性があることを示しています。データバインディングの代わりにGsonのAPI。
これは一般にユーザーコードの実装を大幅に複雑にすることに注意してください。データバインディングAPIを使用するワンライナーに匹敵するソリューションは、たとえば、new Gson().toJson(something)
ループや条件を含む(簡単に)数十行に置き換えられます。したがって、パフォーマンスの向上のコストは、より複雑なコードです。
ストリーミングAPIとデータバインディングAPIの使用例については、jvm-serializersプロジェクトJsonGsonManual
のとJsonGsonDatabind
実装をご覧ください。
(注:ストリーミングまたはデータバインディングAPIの代わりにGson APIでツリーモデルを使用することもできますが、データバインディングよりもパフォーマンスが向上するようには見えません。たとえば、を参照してくださいJsonGsonTree
。)
Gsonは、その使いやすさで知られており、使用されています。スピードが必要な場合は、非常に人気のあるJacksonJsonを確認する必要があります。
私はGsonとJacksonの両方をテストしてベンチマークを行いましたが、非常に大きなオブジェクトであっても、Jacksonはシリアル化と逆シリアル化の両方で15倍高速である場合があります。
Jsonと同様の動作を得るには、次の設定を使用します
public enum JsonMapper {
INSTANCE;
private final ObjectMapper mapper;
private JsonMapper() {
mapper = new ObjectMapper();
VisibilityChecker<?> visibilityChecker = mapper.getSerializationConfig().getDefaultVisibilityChecker();
mapper.setVisibilityChecker(visibilityChecker
.withFieldVisibility(Visibility.ANY)
.withCreatorVisibility(Visibility.NONE)
.withGetterVisibility(Visibility.NONE)
.withSetterVisibility(Visibility.NONE)
.withIsGetterVisibility(Visibility.NONE));
}
public ObjectMapper mapper() {
return mapper;
}
}
これにより、同じオブジェクトのGsonとまったく同じjson文字列が得られます。必要に応じて、ゲッターとセッターのみを使用するように設定できます。サブタイプを処理するためのすべてのjacksonjsonアノテーションについて読むことをお勧めします(RPCスタイルのシステムに役立ちます)。
私のユースケース:blobをストレージシステム(Redis、Cassandra、Mongo、...いつかmysqlも)に保存する必要がある場合は、シリアル化としてjacksonを使用します。また、かなりトラフィックの多いシステムのRPCスタイルのAPIのシリアル化としても使用しますが、可能な場合はProtobufを使用することをお勧めします。この最後のケースでは、パフォーマンスを向上させるために、Jacksonを使用してbyte[]またはストリームに直接シリアル化します。
最後の注意:オブジェクトマッパーはスレッドセーフであり、先ほど送信した例のように静的インスタンスを1つ持つことで、インスタンス化のオーバーヘッドがわずかになるのを防ぐことができます。
編集:私の例は、ジャクソンページで指摘されている多くのベストプラクティスに従っていないことを認識していますが、Gson.toJson
and Gson.fromJson
(私も始めて後でオンに切り替えた)のようなコードを簡単に理解することができますジャクソン)
Gson.toJson(object)
=> JsonMapper.INSTANCE.mapper().writeValueAsString(object)
Gson.fromJson(object, clazz)
=>JsonMapper.INSTANCE.mapper().readValue(jsonString, clazz);
ジャクソンに切り替えて、ベンチマークでGsonよりもはるかに高速な他のソリューションを検討します。
jsonの最適化で重要なのは、すべてのデータを1つのレベルに保持することです。
オブジェクトがそのフィールドとして別のオブジェクトを持ち、このフィールドが別のオブジェクトである場合など、すべてnew
が逆シリアル化に少し時間がかかります。オブジェクトのすべてのフィールドにプリミティブ型がある場合、逆シリアル化は少し速くなります。
ジャクソンとグソンはあなたを助けるための最高の図書館であり続けます。