Простая, беспроблемная сериализация с нулевым разбором в Scala / Java, похожая на Python Pickle? - PullRequest
35 голосов
/ 29 сентября 2011

Существует ли простой, без проблем подход к сериализации в Scala / Java, который похож на рассол Python?Pickle - это очень простое решение, которое достаточно эффективно в пространстве и времени (то есть не является ужасным), но не заботится о межязыковой доступности, управлении версиями и т. Д. И допускает необязательную настройку.

Что яизвестно:

Kryo и protostuff - самые близкие решения, которые я нашел, но мне интересно, есть личто-нибудь еще (или если есть какой-то способ использовать их, о которых я должен знать).Пожалуйста, включите примеры использования!В идеале также включить тесты.

Ответы [ 5 ]

11 голосов
/ 01 октября 2011

Я действительно думаю, что вам лучше всего использовать kryo (я не знаю альтернатив, которые предлагают меньше схем, отличных от недвоичных протоколов).Вы упоминаете, что рассол не подвержен замедлению и раздутию, которое крио получает без регистрации классов, но крио все еще быстрее и менее раздуто, чем рассол, даже без регистрации классов.Посмотрите на следующий микропроцессор (очевидно, что он взят с крошкой соли, но это то, что я мог бы легко сделать):

Python pickle

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    

Выводит 174 байта и 1.18-1.23секунд для меня (Python 2.7.1 в 64-битном Linux)

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

Выводит мне 68 байт и 30-40 мс (Kryo 1.04, Scala 2.9.1, Java1.6.0.26 горячая точка JVM в 64-битном Linux).Для сравнения выводятся 51 байт и 18-25 мс, если я регистрирую классы.

Сравнение

Kryo использует около 40% пространства и 3% времени в качестве Python pickle, когда не регистрируетсяклассы, и около 30% пространства и 2% времени при регистрации классов.И вы всегда можете написать собственный сериализатор, когда вам нужно больше контроля.

9 голосов
/ 18 июня 2013

Scala теперь имеет Scala-травление , которое работает так же хорошо или лучше, чем Kyro, в зависимости от сценария - см. Слайды 34-39 в этой презентации.

6 голосов
/ 26 апреля 2013

Библиотека Twitter chill просто потрясающая.Он использует Kryo для сериализации, но очень прост в использовании.Также приятно: предоставляет тип MeatLocker [X], который делает любой X сериализуемым.

4 голосов
/ 29 сентября 2011

Я бы порекомендовал SBinary . Он использует последствия, которые разрешаются во время компиляции, поэтому он очень эффективен и безопасен для типов. Он поставляется со встроенной поддержкой многих распространенных типов данных Scala. Вы должны вручную написать код сериализации для ваших (case) классов, но это легко сделать.

Пример использования простого ADT

0 голосов
/ 20 марта 2016

Другим хорошим вариантом является недавний (2016 г.) **netvl/picopickle**:

  • Маленький и почти без зависимостей (базовая библиотеказависит только от бесформенного ).
  • Расширяемость : вы можете определить свои собственные сериализаторы для ваших типов и создать собственные бэкэнды, то есть, вы можете использовать одну и ту же библиотеку для разных форматов сериализации (коллекции, JSON, BSON и т. д.);другие части поведения сериализации, такие как обработка нулей, также могут быть настроены.
  • Гибкость и удобство: формат сериализации по умолчанию подходит для большинства применений, но его можно настроить почти произвольно при поддержке со стороныудобные преобразователи DSL.
  • Статическая сериализация без отражения : бесформенные универсальные макросы используются для создания сериализаторов для произвольных типов, что означает, что отражение не используется.

Например:

Средство выбора на основе Jawn также предоставляет дополнительные функции, readString() / writeString() и readAst() / writeAst(), которые [де] сериализуют объекты в строки иJSON AST для строк соответственно:

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")
...