java python scala serialization pickle

La serialización simple, sin complicaciones y cero repeticiones en Scala/Java es similar a la del Pickle de Python.



serialization (5)

¿Hay un enfoque sencillo y sin complicaciones para la serialización en Scala / Java que sea similar al encuadre de Python? Pickle es una solución sencilla que es razonablemente eficiente en el espacio y el tiempo (es decir, no abismal) pero que no se preocupa por la accesibilidad a través del idioma, el control de versiones, etc. y permite la personalización opcional.

De lo que soy consciente:

Kryo y protostuff son las soluciones más cercanas que he encontrado, pero me pregunto si hay algo más por ahí (o si hay alguna forma de usar estos que debería tener en cuenta). Por favor incluya ejemplos de uso! Lo ideal es también incluir puntos de referencia.


De hecho, creo que sería mejor con kryo (no estoy al tanto de las alternativas que ofrecen menos definición de esquema que los protocolos no binarios). Mencionas que pickle no es susceptible a las ralentizaciones e hinchazones que kryo obtiene sin registrar clases, pero kryo es aún más rápido y menos hinchado que pickle incluso sin registrar clases. Vea el siguiente micro-benchmark (obviamente tómelo con un grano de sal, pero esto es lo que podría hacer fácilmente):

Salmuera Python

import pickle import time class Person: def __init__(self, name, age): self.name = name self.age = age people = [Person("Alex", 20), Person("Barbara", 25), Person("Charles", 30), Person("David", 35), Person("Emily", 40)] for i in xrange(10000): output = pickle.dumps(people, -1) if i == 0: print len(output) start_time = time.time() for i in xrange(10000): output = pickle.dumps(people, -1) print time.time() - start_time

Salidas 174 bytes y 1.18-1.23 segundos para mí (Python 2.7.1 en Linux de 64 bits)

Scala kryo

import com.esotericsoftware.kryo._ import java.io._ class Person(val name: String, val age: Int) object MyApp extends App { val people = Array(new Person("Alex", 20), new Person("Barbara", 25), new Person("Charles", 30), new Person("David", 35), new Person("Emily", 40)) val kryo = new Kryo kryo.setRegistrationOptional(true) val buffer = new ObjectBuffer(kryo) for (i <- 0 until 10000) { val output = new ByteArrayOutputStream buffer.writeObject(output, people) if (i == 0) println(output.size) } val startTime = System.nanoTime for (i <- 0 until 10000) { val output = new ByteArrayOutputStream buffer.writeObject(output, people) } println((System.nanoTime - startTime) / 1e9) }

Resultados 68 bytes para mí y 30-40 ms (Kryo 1.04, Scala 2.9.1, Java 1.6.0.26 hotspot JVM en Linux de 64 bits). A modo de comparación, genera 51 bytes y 18-25 ms si registro las clases.

Comparación

Kryo usa aproximadamente el 40% del espacio y el 3% del tiempo como Python pickle cuando no registra clases, y aproximadamente el 30% del espacio y el 2% del tiempo cuando registra clases. Y siempre puede escribir un serializador personalizado cuando desee más control.


La biblioteca de Twitter es simplemente increíble. Utiliza Kryo para la serialización, pero es muy fácil de usar. También es bueno: proporciona un tipo MeatLocker [X] que hace que cualquier X sea serializable.


Otra buena opción es la reciente (2016) **netvl/picopickle** :

  • Pequeño y casi sin dependencia (la biblioteca central solo depende de información).
  • Extensibilidad : puede definir sus propios serializadores para sus tipos y puede crear backends personalizados, es decir, puede usar la misma biblioteca para los diferentes formatos de serialización (colecciones, JSON, BSON, etc.); otras partes del comportamiento de serialización como el manejo de nulos también se pueden personalizar.
  • Flexibilidad y conveniencia: el formato de serialización predeterminado está bien para la mayoría de los usos, pero se puede personalizar de forma casi arbitraria con el soporte de un conveniente convertidor DSL.
  • La serialización estática sin reflexión : sin forma Las macros genéricas se utilizan para proporcionar serializadores para tipos arbitrarios, lo que significa que no se utiliza reflexión.

Por ejemplo:

El pickler basado en Jawn también proporciona funciones adicionales, readString() / writeString() y readAst() / writeAst() , que [de] serializan objetos a cadenas y JSON AST a cadenas, respectivamente:

import io.github.netvl.picopickle.backends.jawn.JsonPickler._ case class A(x: Int, y: String) writeString(A(10, "hi")) shouldEqual """{"x":10,"y":"hi"}""" readString[A]("""{"x":10,"y":"hi"}""") shouldEqual A(10, "hi")


Scala ahora tiene Scala-pickling que se comporta tan bien o mejor que Kyro dependiendo del escenario. Consulte las diapositivas 34-39 en this presentación.


Yo recomendaría SBinary . Utiliza implicits que se resuelven en tiempo de compilación, por lo que es muy efectivo y seguro. Viene con soporte integrado para muchos tipos de datos Scala comunes. Tienes que escribir manualmente el código de serialización para tus clases (caso), pero es fácil de hacer.

Un ejemplo de uso para un ADT simple