我正在尝试使用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序列化程序的性能,我测试了以下代码,它可以序列化相同的Case对象数组,比GSON快大约10倍。
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倍!
答案 0 :(得分:5)
我试图重现你的问题而不能。我创建了7000个具有非平凡数据的对象。在我的ThinkPad上,用Gson~260ms来序列化~3MB的Gson,这是一个可观的~10Mbps。
大部分时间用于将日期转换为字符串。将两个日期字段转换为“long”保存约50ms。
通过从树适配器(JsonSerializer / JsonDeserializer)迁移到新的流适配器类TypeAdaper
,我能够节省大约10ms。设置此代码的代码如下所示:
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类。但是,如果Key是手动序列化每个案例时应该出现的瓶颈。
解决问题
您最好的下一步是从Case
中删除字段,直到序列化改进为止。您的某个字段可能包含需要很长时间才能序列化的内容:可能是需要过多转义的非常长的字符串?一旦您将问题report a bug隔离到Gson项目,我们将很乐意解决问题。除了包含重现问题的代码之外,您还应该包含代表性数据。
答案 1 :(得分:1)