Scala/Java中简单,无忧,零样板序列化,类似于Python的Pickle?

2022-09-01 05:26:07

有没有一种简单,无忧无虑的Scala / Java序列化方法,类似于Python的泡菜?Pickle是一个非常简单的解决方案,在空间和时间上相当有效(即不是糟糕),但不关心跨语言可访问性,版本控制等,并允许可选的自定义。

我所知道的:

  • Java的内置序列化是臭名昭着的缓慢([1][2]),臃肿和脆弱。还必须将类标记为可序列化---当存在明显可序列化但没有该注释的内容时(例如,没有多少Point2D作者标记这些可序列化)。
  • Scala的BytePickle需要一堆样板文件来表达你想要泡菜的每种类型,即使这样,它也不适用于(循环)对象图
  • jserial:未维护,似乎并不比默认的Java序列化快/小得多
  • kryo无法(反)序列化没有 0-arg ctor 的对象,这是一个严重的限制。(此外,您必须注册计划序列化的每个类,否则您会遇到显着的减速/膨胀,但即使如此,它仍然比泡菜快。
  • 原型:AFAICT,您必须在“模式”中提前注册要序列化的每个类。

Kryo和protostuff是我发现的最接近的解决方案,但我想知道是否还有其他东西(或者是否有一些我应该注意的使用这些方法)。请包括使用示例!理想情况下,还包括基准测试。


答案 1

我实际上认为你最好使用kryo(我不知道除了非二进制协议之外,提供较少模式定义的替代方案)。你提到泡菜不容易受到 kryo 在没有注册类的情况下得到的减速和膨胀的影响,但即使没有注册类,kryo 仍然比泡菜更快,更不臃肿。请参阅以下微基准测试(显然可以放心,但这是我可以轻松做到的):

蟒蛇泡菜

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-40ms(Kryo 1.04,Scala 2.9.1,Java 1.6.0.26热点JVM在64位Linux上)。为了进行比较,如果我注册类,它输出51个字节和18-25ms。

比较

Kryo在不注册类时使用大约40%的空间和3%的时间作为Python泡菜,在注册类时大约30%的空间和2%的时间。当您需要更多控制时,您始终可以编写自定义序列化程序。


答案 2

Edit 2020-02-19:请注意,正如下面@federico所述,此答案不再有效,因为存储库已由所有者存档。

Scala 现在具有 Scala 酸洗,其性能与 Kyro 一样好或更好,具体取决于场景 - 请参阅演示中的幻灯片 34-39。