在上一篇博文中提到,Spark任务中,使用序列化数据的方式对增加其执行效率有很大的作用。并且由于Kryo序列化方式在主动注册自定义类的情况下,无论是序列化速度还是序列化结果的大小,都比Java自身的序列化方式要好。在这篇文章中将根据代码实例来纵向对比Kryo在注册了自定义类、没有注册自定义类下的序列化结果,以及横向对比Kryo和Java两者序列化的时间和结果。
Kryo横向对比
本小节通过使用Kryo和Java两种序列化方式对统一对象进行序列化,并观察其在序列化过程中所用的时间长短及序列化后结果的大小,以此作为判断其性能优劣的指标。验证代码如下:
class TestKryo$Test extends FunSuite {
test("KryoTest"){
val filledArray: Array[Position] = Array.fill(1000)(new Position(0.2,0.3))
val kryo: Kryo = new Kryo()
kryo.register(classOf[recruit.scalar.com.elevenbee.work.bean.model.personcluster.Position])//手动注册
kryo.register(classOf[Array[Position]])
kryo.setReferences(false)
kryo.setInstantiatorStrategy(new StdInstantiatorStrategy)
val output: Output = new Output()
val outPutStream: BufferedOutputStream = new BufferedOutputStream(new FileOutputStream("byte.bin"))
output.setOutputStream(outPutStream)
val bytes: Array[Byte] = new Array[Byte](1000000)
output.setBuffer(bytes)
val stopwatch: Stopwatch = Stopwatch.createStarted()
kryo.writeClassAndObject(output,filledArray)
println("Kryo序列化所用时间 "+stopwatch.elapsed(TimeUnit.MILLISECONDS))
println("Kryo序列化后的字节数组大小为 "+bytes.count(_!='\0'))
println("Kryo序列化后的结果为")
println(new String(bytes))
val byteArrayOutputStream: ByteArrayOutputStream = new ByteArrayOutputStream(1000000)
val objectOutputStream: ObjectOutputStream = new ObjectOutputStream(byteArrayOutputStream)
stopwatch.reset()
stopwatch.start()
objectOutputStream.writeObject(filledArray)
println("Java序列化所用时间 "+stopwatch.elapsed(TimeUnit.MILLISECONDS))
val byteArray: Array[Byte] = byteArrayOutputStream.toByteArray
println("Java序列化后的字节数组大小为 "+byteArrayOutputStream.toByteArray.count(_!='\0'))
println("Java序列化后的字节数组结果为")
println(new String(byteArray))
output.close()
outPutStream.close()
}
}
可以看到,在代码中使用两种序列化方式对同一个Array进行序列化,并打印了其序列化时间及结果,运行结果如下:
Kryo序列化所用时间 17
Kryo序列化后的字节数组大小为 17003
Kryo序列化后的结果为
�?�333333?ə�����?�333333?ə�����...重复一千次
Java序列化所用时间 112
Java序列化后的字节数组大小为 20177
Java序列化后的字节数组结果为
�� ur F[Lrecruit.scalar.com.elevenbee.work.bean.model.personcluster.Position;a)���� xp �sr Crecruit.scalar.com.elevenbee.work.bean.model.personcluster.Position)�4�7��� D latD lngxp?�333333?ə�����sq ~ ...重复一千次
可以看到,在手动向Kryo注册了Array和Position类后,Kryo无论是序列化时间还是序列化结果都比Java的序列化要优秀很多。
纵向对比
纵向对比主要对比Kryo 在主动注册自定义类和不注册自定义类的情况下,其各自的序列化效率。
class TestKryo$Test extends FunSuite {
test("KryoTest"){
val filledArray: Array[Position] = Array.fill(1000)(new Position(0.2,0.3))
val kryo: Kryo = new Kryo()
kryo.register(classOf[recruit.scalar.com.elevenbee.work.bean.model.personcluster.Position])//手动注册
kryo.register(classOf[Array[Position]])
kryo.setReferences(false)
kryo.setInstantiatorStrategy(new StdInstantiatorStrategy)
val output: Output = new Output()
val bytes: Array[Byte] = new Array[Byte](1000000)
output.setBuffer(bytes)
val stopwatch: Stopwatch = Stopwatch.createStarted()
kryo.writeClassAndObject(output,filledArray)
println("Kryo序列化所用时间 "+stopwatch.elapsed(TimeUnit.MILLISECONDS))
println("Kryo序列化后的字节数组大小为 "+bytes.count(_!='\0'))
println("Kryo序列化后的结果为")
println(new String(bytes))
output.close()
}
}
测试代码如上所示,注册了全部的自定义类后的序列化结果正如横向对比中所示,不再赘述。这里测试在不注册其中两个自定义类的情况下,其序列化效率。在不注册Array而注册Position的情况下,序列化结果如下所示:
Kryo序列化所用时间 71
Kryo序列化后的字节数组大小为 17075
Kryo序列化后的结果为
�[Lrecruit.scalar.com.elevenbee.work.bean.model.personcluster.Position;�?�333333?ə�����...重复1000次
可以看到序列化内容中增加了一段全限定名表示是Position的数组类型,并且序列化时间瞬间涨了4倍多。在不注册Position而注册了Array的情况下的情况下,序列化信息如下所示:
Kryo序列化所用时间 64
Kryo序列化后的字节数组大小为 17072
Kryo序列化后的结果为
� �recruit.scalar.com.elevenbee.work.bean.model.personcluster.Position?�333333?ə�����...重复1000次
可以看到其序列化内容与只注册Position的大小类似,且序列化时间也差不多。在两者都不注册的情况下,其序列化信息如下
Kryo序列化所用时间 74
Kryo序列化后的字节数组大小为 18144
Kryo序列化后的结果为
�[Lrecruit.scalar.com.elevenbee.work.bean.model.personcluster.Position;��recruit.scalar.com.elevenbee.work.bean.model.personcluster.Position?�333333?ə�����...重复1000次
可以看到无论是序列化时间还是序列化内容都会增加。