2012-05-21 2 views
10

Я пытаюсь сериализовать массив из 7000 POJO с помощью GSON, и время сериализации очень медленное. Это порядка 3-5 секунд, чтобы сериализовать массив следующего объекта:GSON Сериализация очень очень медленная

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 примерно в 10 раз быстрее, чем 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(); 

Любые идеи, почему 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 раз производительность!

+0

Какие gson версию вы используете, и то, что ваш код, чтобы получить выход? – Joey

+0

Я использую gson 2.2, обновляю вопрос с кодом для создания вывода – aloo

+0

Как вы создаете свой объект Gson? –

ответ

4

Я попытался воспроизвести вашу проблему и не смог. Я создал 7000 объектов с нетривиальными данными в них. На моем ThinkPad потребовался Gson ~ 260 мс для сериализации ~ 3 МБ Gson, который является респектабельным ~ 10 Мбит/с.

Большая часть времени была потрачена на преобразование дат в строки. Преобразование двух полей даты в «длинные» сохраненные около 50 мс.

Я смог сохранить еще ~ 10 мс, перенеся из адаптеров дерева (JsonSerializer/JsonDeserializer) в новый класс адаптера потоковой передачи 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(); 

Основное различие между моим сценарием и вашим в том, что я использую свой собственный поддельный ключ класс. Но если ключ был узким местом, которое должно было возникнуть, когда вы вручную сериализовали каждый случай.

Решение проблемы

Ваш лучший следующий шаг должен удалить поля из Case до сериализации улучшается. Возможно, что одно из ваших полей содержит то, что занимает много времени для сериализации: возможно, очень длинная строка, требующая чрезмерного ускорения? Как только вы изолируете проблему report a bug до проекта Gson, мы с радостью исправим проблему.Помимо включения кода , который воспроизводит проблему, вы также должны указать представитель данные.

+0

Если это чрезмерное ускорение, проблема не будет отображаться в ручной сериализации? – aloo

+0

Теперь попробуйте свои другие стратегии – aloo

+0

Хорошо, я попробовал стратегию TypeAdapter и, похоже, не очень-то помогает. Интересно, что версия моего кода, которая сериализуется «вручную», не только сериализует те же самые поля (ключи, даты и т. Д.), Используя ту же методологию, что и TypeAdapters, но она работает буквально в 20 раз быстрее. Кажется, что это неправильно с самой библиотекой gson. – aloo

Смежные вопросы