2012-05-21 12 views
10

Estoy tratando de serializar una matriz de 7000 POJO utilizando GSON y el tiempo de serialización es extremadamente lento. Es del orden de 3-5 segundos para serializar un conjunto de los siguientes objetos:GSON Serialización muy muy lenta

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

Los campos clave se serializan con un serializador personalizado/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); 
} 
} 

Para probar el rendimiento frente a la mano escribiendo un serializador JSON, probé el siguiente código y podría serializar la misma matriz de objetos Case aproximadamente 10 veces más rápido que 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(); 

¿Alguna idea de por qué GSON está funcionando tan mal en este caso?

ACTUALIZACIÓN

Aquí está el código que empieza realmente la serialización:

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

Update2

He aquí un caso de prueba muy simple que ilustra el comportamiento pobres en relación con 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)); 

donde foo es:

public class Foo { 
public Long id; 
} 

Este salidas:

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

casi 10x diferencia de rendimiento!

+0

Qué GSON qué versión está utilizando y qué es el código para producir la salida? – Joey

+0

Estoy usando gson 2.2, actualizando la pregunta con el código para producir la salida – aloo

+0

¿Cómo se crea el objeto Gson? –

Respuesta

4

Yo intento de reproducir su problema y no pudieron. Creé 7000 objetos con datos no triviales en ellos. En mi ThinkPad gister ~ 260ms para serializar ~ 3MB de Gson, que es un respetable ~ 10Mbps.

Una gran parte de ese tiempo lo pasó la conversión de fechas para las cadenas. La conversión de los dos campos de fecha a 'largo' se guardó alrededor de 50 ms.

Pude guardar otros ~ 10ms migrando desde adaptadores de árbol (JsonSerializer/JsonDeserializer) a la nueva clase de adaptador de transmisión TypeAdaper. El código que establece esto se ve así:

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

La principal diferencia entre mi escenario y el suyo es que estoy usando mi propia clase clave falsa. Pero si la clave era el cuello de botella que debería haber surgido cuando serializó manualmente cada caso.

Arreglar el problema

Su mejor siguiente paso es eliminar los campos de Case hasta serialización mejora. Es posible que uno de tus campos contenga algo que lleva mucho tiempo serializar: ¿quizás una cadena muy larga que requiera un escape excesivo? Una vez que aísle el problema report a bug en el proyecto Gson, con gusto solucionaremos el problema.Además de incluir el código que reproduce el problema, también debe incluir los datos del representante .

+0

Si se trata de un escape excesivo el problema no sería esto aparecer en la serialización manual también? – aloo

+0

Probando sus otras estrategias ahora – aloo

+0

Ok Probé la estrategia TypeAdapter y no parece ayudar mucho. Lo que es interesante es que la versión de mi código que serializa "a mano", no solo serializa los mismos campos (claves, fechas, etc.) usando la misma metodología que TypeAdapters, sino que se ejecuta literalmente 20 veces más rápido. Esto parece estar mal con la biblioteca gson en sí misma. – aloo