我试图使用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,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在这种情况下表现如此糟糕?
UPDATE
以下是实际启动序列化的代码:
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倍的性能差异!
解决方法
我试图重现你的问题,不能.我在其中创建了7000个具有非平凡数据的对象.在我的ThinkPad上,Gson〜260ms串行化〜3MB的Gson,这是一个可观的〜10Mbps.
大部分时间用于将日期转换为字符串.将两个日期字段转换为“长”保存约50ms.
通过从树型适配器(JsonSerializer / JsonDeserializer)迁移到新的流式适配器ClassAdaper类,我可以保存另外约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项目隔离开来,我们将很乐意解决问题.除了包含重现问题的代码之外,还应包括代表性数据.