Scala / Java中是否有一种简单,无障碍的序列化方法,类似于Python的pickle? Pickle是一个简单易懂的解决方案,在空间和时间上相当有效(即不是很糟糕),但不关心跨语言的可访问性,版本控制等,并允许可选的自定义。
我所知道的:
Kryo和protostuff是我找到的最接近的解决方案,但我想知道是否还有其他任何东西(或者是否有某些方法可以使用这些我应该注意的)。请包括用法示例!理想情况下还包括基准。
答案 0 :(得分:11)
我实际上认为你最好用kryo(我不知道除了非二进制协议之外提供更少模式定义的替代方案)。你提到泡菜不容易受到kryo没有注册课程的减速和膨胀的影响,但即使没有注册课程,kryo仍然比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秒(64位Linux上的Python 2.7.1)
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)类的序列化代码,但这很容易。
答案 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")