GSON序列化非常慢 [英] GSON Serialization very very slow

查看:208
本文介绍了GSON序列化非常慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用GSON序列化一个7000 POJO阵列,并且序列化时间非常缓慢。序列化下列对象的数组大约需要3-5秒的时间:

  public class Case {
私人long caseId;
私钥<组织> orgKey;

私钥<工作流程> workflowKey;
私钥<用户> creatorKey;

私人日期creationTimestamp;
私人日期lastUpdatedTimestamp;

私人字符串名称;
私人字符串阶段;
私人字符串笔记;



$ b

使用自定义序列化器/反序列化器对关键字段进行序列化:

  public class GsonKeySerializerDeserializer实现JsonSerializer< Key<>>,JsonDeserializer< Key<>> {

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

@Override
公共密钥<?> deserialize(JsonElement src,Type typeOfSrc,JsonDeserializationContext arg2)抛出JsonParseException {
if(src.isJsonNull()|| src.getAsString()。isEmpty()){
return null;
}

String s = src.getAsString();
com.google.appengine.api.datastore.Key k = KeyFactory.stringToKey(s);
返回新密钥(k);




$ b $ p
$ b为了测试手写JSON串行器的性能,我测试了下面的代码,它可以序列化大约比GSON快10倍的Case对象。

 列表< Case>例子=(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
<

  List< Foo>下面是一个非常简单的测试用例,说明了相对于org.json的糟糕表现: 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(使用Gson的序列化时间:+((double)(System.currentTimeMillis() - start)/ 1000));


start = System.currentTimeMillis();
JSONArray a = new JSONArray(); (foo f:list){
JSONObject o = new JSONObject();

o.put(id,f.id);
a.put(o);

}
String json = a.toString();
System.out.println(使用org.json的序列化时间:+((double)(System.currentTimeMillis() - start)/ 1000));

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

其中Foo是:

  public class Foo {
public Long id;
}

输出:

 使用Gson的序列化时间:0.233 
使用org.json的序列化时间:0.028
true

差不多有10倍的表现差异!

解决方案

我试图重现您的问题并且不能。我创建了7000个对象,其中包含非平凡的数据。在我的ThinkPad上,Gson花费了260ms来串行化〜3MB的Gson,这是一个可观的〜10Mbps。

大部分时间花在将日期转换为字符串上。通过从树适配器(JsonSerializer / JsonDeserializer)迁移到新的流式传输,我能够节省另一个〜10ms的时间适配器类 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)抛出IOException {
if(in.peek()== JsonToken.NULL){
in.nextNull();
返回null;
}
返回新的键< String>(in.nextString());
}
};

...

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

我的场景和你的场景之间的主要区别是我使用我自己的伪造的Key类。但是,如果密钥是手动序列化每个病例时出现的瓶颈。



解决问题



最好的下一步是从 Case 中删除​​字段,直到序列化得到改善。您的某个字段可能包含需要很长时间才能序列化的内容:可能是需要过度转义的非常长的字符串?一旦您将问题报告bug 报告给Gson项目,我会很高兴地解决这个问题。除了包含重现问题的代码,您还应该包含代表性的数据


I'm trying to serialize an array of 7000 POJO using GSON and the serialization time is extremely slow. It's on the order of 3-5 seconds to serialize an array of the following object:

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;
}

The key fields are serialized using a custom serializer/deserializer:

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);
}
}

To test the performance against hand writing a JSON serializer, I tested the following code and it could serialize the same array of Case objects approximately 10x faster than GSON.

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();

Any ideas why GSON is performing so badly in this case?

UPDATE

Here's the code that actually starts the serialization:

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

UPDATE2

Here's a very simple test case that illustrates the poor performance relative to 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));

Where Foo is:

public class Foo {
public Long id;
}

This outputs:

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

An almost 10x performance difference!

解决方案

I attempted to reproduce your problem and could not. I created 7000 objects with nontrivial data in them. On my ThinkPad it took Gson ~260ms to serialize ~3MB of Gson, which is a respectable ~10Mbps.

A large fraction of that time was spent converting dates to strings. Converting the two date fields to 'long' saved about 50ms.

I was able to save another ~10ms by migrating from tree adapters (JsonSerializer/JsonDeserializer) to the new streaming adapter class TypeAdaper. The code that sets this up looks like this:

    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();

The main difference between my scenario and yours is that I'm using my own bogus Key class. But if the Key was the bottleneck that should have come up when you manually serialized each case.

Fixing the problem

Your best next step is to remove fields from Case until serialization improves. It's possible that one of your fields contains something that's taking a long time to serialize: perhaps a very long string that requires excessive escaping? Once you isolate the problem report a bug to the Gson project and we'll happily fix the problem. In addition to including the code that reproduces the problem you should also include representative data.

这篇关于GSON序列化非常慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆