12

GSON を使用して 7000 個の POJO の配列をシリアル化しようとしていますが、シリアル化時間が非常に遅くなります。次のオブジェクトの配列をシリアル化するには、3 ~ 5 秒程度かかります。

public class Case {
    private Long caseId;
    private Key<Organization> orgKey;

    private Key<Workflow> workflowKey;
    private Key<User> creatorKey;

    private Date creationTimestamp;
    private Date lastUpdatedTimestamp;

    private String name;
    private String stage;
    private String notes;
}

キー フィールドは、カスタム シリアライザー/デシリアライザーを使用してシリアル化されます。

public class GsonKeySerializerDeserializer implements JsonSerializer<Key<?>>, JsonDeserializer<Key<?>>{

@Override
public JsonElement serialize(Key<?> src, Type typeOfSrc, JsonSerializationContext arg2) {
    return new JsonPrimitive(src.getString());
}

@Override
public Key<?> deserialize(JsonElement src, Type typeOfSrc, JsonDeserializationContext arg2) throws JsonParseException {
    if (src.isJsonNull() || src.getAsString().isEmpty()) {
        return null;
    }

    String s = src.getAsString();
    com.google.appengine.api.datastore.Key k = KeyFactory.stringToKey(s);
    return new Key(k);
}
}

JSON シリアライザーの手書きに対するパフォーマンスをテストするために、次のコードをテストしたところ、GSON よりも約 10 倍速く Case オブジェクトの同じ配列をシリアライズできました。

List<Case> cases = (List<Case>) retVal;
JSONArray a = new JSONArray();
for (Case c : cases) {
    JSONObject o = new JSONObject();
    o.put("caseId", c.getCaseId());
    o.put("orgKey", c.getOrgKey().getString());
    o.put("workflowKey", c.getWorkflowKey().getString());
    o.put("creatorKey", c.getCreatorKey().getString());
    o.put("creationTimestamp", c.getCreationTimestamp().getTime());
    o.put("lastUpdatedTimestamp", c.getLastUpdatedTimestamp().getTime());
    o.put("name", c.getName());
    o.put("stage", c.getStage());
    o.put("notes", c.getNotes());
    a.put(o);

}
String json = a.toString();

この場合、GSON のパフォーマンスが非常に悪い理由はありますか?

アップデート

実際にシリアル化を開始するコードは次のとおりです。

Object retVal = someFunctionThatReturnsAList();
String json = g.toJson(retVal);
resp.getWriter().print(json);

UPDATE2

以下は、org.json に比べてパフォーマンスが低いことを示す非常に単純なテスト ケースです。

List<Foo> list = new ArrayList<Foo>();
for (int i = 0; i < 7001; i++) {
    Foo f = new Foo();
    f.id = new Long(i);
    list.add(f);
}

Gson gs = new Gson();
long start = System.currentTimeMillis();
String s = gs.toJson(list);
System.out.println("Serialization time using Gson: " + ((double) (System.currentTimeMillis() - start) / 1000));


start = System.currentTimeMillis();
JSONArray a = new JSONArray();
for (Foo f : list) {
    JSONObject o = new JSONObject();
    o.put("id", f.id);
    a.put(o);

}
String json = a.toString();
System.out.println("Serialization time using org.json: " + ((double) (System.currentTimeMillis() - start) / 1000));

System.out.println(json.equals(s));

Foo の場所:

public class Foo {
public Long id;
}

これは以下を出力します:

Serialization time using Gson: 0.233
Serialization time using org.json: 0.028
true

約10倍の性能差!

4

2 に答える 2

6

問題を再現しようとしましたが、できませんでした。重要なデータを含む 7000 個のオブジェクトを作成しました。私の ThinkPad では、Gson が ~3MB の Gson をシリアライズするのに ~260ms かかりました。これは立派な ~10Mbps です。

その時間の大部分は、日付を文字列に変換するのに費やされました。2 つの日付フィールドを「long」に変換すると、約 50 ミリ秒短縮されました。

ツリー アダプター (JsonSerializer/JsonDeserializer) から新しいストリーミング アダプター クラスに移行することで、さらに 10 ミリ秒を節約できましたTypeAdaper。これを設定するコードは次のようになります。

    private static TypeAdapter<Key<String>> keyAdapter = new TypeAdapter<Key<String>>() {
        @Override public void write(JsonWriter out, Key<String> value) throws IOException {
            out.value(value.value);
        }

        @Override public Key<String> read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return null;
            }
            return new Key<String>(in.nextString());
        }
    };

    ...

    Gson gson = new GsonBuilder()
            .registerTypeAdapter(Key.class, keyAdapter)
            .create();

私のシナリオとあなたのシナリオの主な違いは、私が独自の偽の Key クラスを使用していることです。ただし、各ケースを手動でシリアル化するときに発生するはずだったボトルネックがキーである場合。

問題の修正

次の最善のステップは、Caseシリアル化が改善されるまでフィールドを削除することです。フィールドの 1 つに、シリアル化に時間がかかるものが含まれている可能性があります。おそらく、過度のエスケープが必要な非常に長い文字列ですか? 問題を特定したら、バグを Gson プロジェクトに報告してください。喜んで問題を修正します。問題を再現するコードを含めることに加えて、代表的なデータも含める必要があります。

于 2012-05-22T14:26:36.773 に答える
1

json でフラット バッファを使用するのはどうですか。

https://medium.freecodecamp.com/why-consider-flatbuffer-over-json-2e4aa8d4ed07#.d79exjq8n

于 2016-09-09T09:45:02.110 に答える