2009-03-02 18 views
5

Debo serializar un enorme árbol de objetos (7,000) en el disco. Originalmente mantuvimos este árbol en una base de datos con Kodo, pero generaría miles y miles de consultas para cargar este árbol en la memoria, y tomaría una buena parte del tiempo disponible del universo local.Java Object Serialization Performance tips

Intenté la serialización para esto y, de hecho, obtuve una mejora en el rendimiento. Sin embargo, tengo la sensación de que podría mejorar escribiendo mi propio código de serialización personalizado. Necesito hacer la carga de este objeto serializado lo más rápido posible.

En mi máquina, la serialización/deserialización de estos objetos lleva unos 15 segundos. Al cargarlos desde la base de datos, demora alrededor de 40 segundos.

¿Algún consejo sobre qué podría hacer para mejorar este rendimiento, teniendo en cuenta que debido a que los objetos están en un árbol, se hacen referencia el uno al otro?

Respuesta

6

Una optimización es la personalización de los descriptores de clase, para que almacene los descriptores de clase en una base de datos diferente y en la secuencia de objetos solo se hace referencia a ellos por ID. Esto reduce el espacio que necesitan los datos serializados. Ver por ejemplo cómo en un proyecto las clases SerialUtil y ClassesTable lo hacen.

Hacer clases Externalizable en lugar de Serializable puede proporcionar algunos beneficios de rendimiento. La desventaja es que requiere mucho trabajo manual.

Luego hay otras bibliotecas de serialización, por ejemplo jserial, que pueden ofrecer un mejor rendimiento que la serialización predeterminada de Java.Además, si el gráfico de objetos no incluye ciclos, se puede serializar un poco más rápido, porque el serializador no necesita realizar un seguimiento de los objetos que ha visto (consulte "¿Cómo funciona?" En jserial's FAQ).

+1

He hecho la ruta Externalizable en el pasado, y obtuve aproximadamente un 20-23% de aumento en el rendimiento en la serialización/deserialización de gráficos de objetos grandes. La cantidad de trabajo requerida para esto será proporcional a la cantidad de objetos que debe personalizar. – Robin

+0

Solo pago y envío http://code.google.com/p/fast-serialization/. Problema resuelto :-) –

1

¿Ha intentado comprimir la corriente (GZIPOutputStream)?

+0

Necesito un mejor rendimiento en la carga y el almacenamiento, pero no especifiqué en la pregunta y, de hecho, el espacio también es una medida de "rendimiento". –

+0

Menos espacio significa menos acceso a disco significa menos tiempo –

+0

solo si el proceso de serialización está en disco.no parece estar en mi sistema; parece estar unida a la CPU, por lo que la compresión lo ralentizará aún más. –

1

Esta es la forma en que lo haría, forman la parte superior de mi cabeza

serialización

  1. Serialize cada objeto individual
  2. Asignar a cada objeto un único clave
  3. Cuando un objeto tiene una referencia a otro objeto, coloque la clave única para ese objeto en el lugar de los objetos en la serialización. (Me gustaría utilizar un UUID convertido a binario)
  4. Guardar cada objeto en un fichero/base de datos/almacenamiento utilizando la clave única

Unserialization

  1. COMIENZO Módulo de un objeto arbitrario (por lo general la raíz i sospechoso) deserializarlo y ponerlo en un mapa con su clave única como índice y devolverlo
  2. Cuando pise una clave de objeto en la secuencia de serialización, primero compruebe si ya se ha deserializado buscando su clave única en el mapa y si es simplemente tomarlo de allí, si no poner un proxy de carga perezosa (que repite estos dos pasos para ese objeto) en lugar del objeto real que tiene ganchos para cargar el objeto correcto cuando lo necesite.

Editar, es posible que tenga que utilizar la serialización de dos pasadas y unserialization si tiene referencias circulares en allí, que complica las cosas un poco - pero no tanto.

+0

Eso podría funcionar, pero requeriría volver a trabajar bastante parte del código que tengo –

+0

¿Cómo sería eso una mejora sobre la serialización estándar? Hasta donde sé, eso ya lo hizo el mecanismo predeterminado. –

+0

@saua porque puede cargar y crear instancias de forma lenta cada objeto cuando sea necesario en lugar de cargarlo todo de una vez, también puede bajar el nivel de bytes usted mismo y optimizar el formato de serialización. – thr

0

Para el rendimiento, sugiero no utilizar la serialización de java.io en absoluto. En lugar de eso, desciende a los bytes tú mismo.

Si va a serializar el árbol en java.io, puede necesitar asegurarse de que su recursión no sea demasiado profunda, ya sea aplanando (como dice TreeSet si) o haciendo arreglos para serializar primero los nodos más profundos (para que tiene referencias anteriores en lugar de llamadas anotadas readObject).

Me sorprendería que Kodo no tuviera forma de leer el árbol completo en uno (o algunos).

+0

Kodo tiene una forma de hacerlo, pero el problema es que depende de cómo se crean los objetos en la base de datos. Desafortunadamente, la base de datos es de tal manera que no podemos hacerlo (y no hay manera de cambiar el modelo) –

10

No olvide utilizar la palabra clave 'transitoria', por ejemplo, variables que no tienen que ser serializadas. Esto le da un aumento de rendimiento porque ya no está leyendo/escribiendo datos innecesarios.

+0

Esa es una buena consideración general importante en cualquier caso. Ya lo hago, pero es importante mencionarlo. +1 –

4

Se lo recomiendo a implementar encargo writeObject() y readObject() métodos. De esta manera, podrá enviar nodos de chidren de escritura para cada nodo en un árbol. Cuando utiliza la serialización predeterminada, cada nodo se serializará con todos sus elementos secundarios.

Por ejemplo, writeObject() de una clase de árbol debe recorrer todos los nodos de un árbol y sólo escribir datos en los nodos (nodos sin sí mismo) con algunos marcadores, que identifica el nivel de árbol.

Puede consultar LinkedList, para ver cómo se implementan estos métodos allí. Utiliza el mismo enfoque para evitar escribir entradas previas y siguientes para cada entrada individual.

4

Para evitar tener que escribir su propio código de serialización, pruebe Google Protocol Buffers. De acuerdo con su sitio:

Los buffers de protocolo son el mecanismo independiente de la plataforma neutral de idioma de Google para serializar datos estructurados, piense en XML, pero más pequeño, más rápido y más simple. Usted define cómo desea que sus datos se estructuren una vez, luego puede usar un código fuente especial generado para escribir y leer fácilmente sus datos estructurados desde y hacia una variedad de flujos de datos y utilizando una variedad de idiomas: Java, C++ o Python

No lo he usado, pero he escuchado muchas cosas positivas al respecto. Además, tengo que mantener algún código de serialización personalizado, y puede ser una pesadilla absoluta (y mucho menos rastrear errores), por lo que hacer que otra persona lo haga por usted siempre es una buena cosa.

0

Además, eche un vistazo a XStream, una biblioteca para serializar objetos a XML y viceversa.

+0

Lo he intentado ya, para este tipo de objetos es incluso peor que Kodo. La serialización de Java es mucho más rápida que XStream. –

0

Puede usar Colfer para generar los beans y el rendimiento de serialización estándar de Java obtendrá un aumento de 10 - 1000x. A menos que el tamaño alcance más de un GB, es probable que esté muy por debajo de un segundo.