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

时间:2011-09-28 22:47:14

标签: java python scala serialization pickle

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

我所知道的:

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

5 个答案:

答案 0 :(得分:11)

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

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    

为我输出174个字节和1.18-1.23秒(64位Linux上的Python 2.7.1)

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

为我和30-40ms输出68个字节(Kryo 1.04,Scala 2.9.1,64位Linux上的Java 1.6.0.26热点JVM)。为了比较,如果我注册类,它输出51个字节和18-25ms。

比较

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

答案 1 :(得分:9)

Scala现在有Scala-pickling,其表现与Kyro一样好或更好,具体取决于场景 - 请参阅this演示文稿中的幻灯片34-39。

答案 2 :(得分:6)

Twitter的chill library真棒。它使用Kryo进行序列化,但使用起来非常简单。同样不错:提供一个MeatLocker [X]类型,它使任何X成为Serializable。

答案 3 :(得分:4)

我会推荐SBinary。它使用在编译时解决的implicits,因此它非常有效且类型安全。它内置了对许多常见Scala数据类型的支持。您必须手动编写(case)类的序列化代码,但这很容易。

A usage example for a simple ADT

答案 4 :(得分:0)

另一个不错的选择是最近的(2016)**netvl/picopickle**

  
      
  • 且几乎无依赖(核心库仅取决于 shapeless )。
  •   
  • 可扩展性:您可以为您的类型定义自己的序列化器,并且您可以创建自定义后端,也就是说,您可以将相同的库用于不同的序列化格式(集合,JSON,BSON等) );序列化行为的其他部分(如空值处理)也可以自定义。
  •   
  • 灵活性和便利性:默认的序列化格式适用于大多数用途,但它可以在方便的转换器DSL的支持下几乎任意定制。
  •   
  • 无反射的静态序列化:无形通用宏用于为任意类型提供序列化,这意味着不使用反射。
  •   

例如:

  

基于Jawn的pickler还提供了其他函数readString() / writeString()readAst() / writeAst(),其中[de]将对象序列化为字符串,将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")