高性能的序列化與反序列化:kryo的簡單使用


前言:kryo是個高效的java序列化/反序列化庫,目前Twitter、yahoo、Apache、strom等等在使用該技術,比如Apache的spark、hive等大數據領域用的較多。

為什么使用kryo而不是其他?

因為性能足夠好。比kyro更高效的序列化庫就只有google的protobuf了(而且兩者性能很接近),protobuf有個缺點就是要傳輸的每一個類的結構都要生成對應的proto文件(也可以都放在同一個proto文件中,如果考慮到擴展性的話,不建議放在一個proto文件中),如果某個類發生修改,還得重新生成該類對應的proto文件;另外考慮到項目中用的全部是java技術棧,不存在不同編程語言間的兼容性問題,因此最終采用了kryo作為序列化庫。

使用場景:(數據交換或數據持久化)比如使用kryo把對象序列化成字節數組發送給消息隊列或者放到redis等nosql中等等應用場景。

注意:由於kryo不是線程安全的,針對多線程情況下的使用,要對kryo進行一個簡單的封裝設計,從而可以多線程安全的使用序列化和反序列化

序列化和反序列化接口設計


   
   
  
  
          
  1. /**
  2. * 序列化工具(程序調用該接口來實現obj<->byte[]之間的序列化/反序列化)
  3. * @author eguid
  4. *
  5. */
  6. public interface Serializer{
  7. /**
  8. * 序列化
  9. * @param t
  10. * @param bytes
  11. */
  12. public void serialize(Object t,byte[] bytes);
  13. /**
  14. * 序列化
  15. * @param obj
  16. * @param bytes
  17. * @param offset
  18. * @param count
  19. */
  20. public void serialize(Object obj, byte[] bytes, int offset, int count);
  21. /**
  22. * 反序列化
  23. * @param bytes -字節數組
  24. * @return T<T>
  25. */
  26. public <T> T deserialize(byte[] bytes);
  27. /**
  28. * 反序列化
  29. * @param bytes
  30. * @param offset
  31. * @param count
  32. * @return
  33. */
  34. public <T> T deserialize(byte[] bytes, int offset, int count);
  35. }

使用kryo實現上面的接口


   
   
  
  
          
  1. /**
  2. * 基於kyro的序列化/反序列化工具
  3. *
  4. * @author eguid
  5. *
  6. */
  7. public class kryoSerializer implements Serializer {
  8. // 由於kryo不是線程安全的,所以每個線程都使用獨立的kryo
  9. final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() {
  10. @Override
  11. protected Kryo initialValue() {
  12. Kryo kryo = new Kryo();
  13. kryo.register(ct, new BeanSerializer<>(kryo, ct));
  14. return kryo;
  15. }
  16. };
  17. final ThreadLocal<Output> outputLocal = new ThreadLocal<Output>();
  18. final ThreadLocal<Input> inputLocal = new ThreadLocal<Input>();
  19. private Class<?> ct = null;
  20. public kryoSerializer(Class<?> ct) {
  21. this.ct = ct;
  22. }
  23. public Class<?> getCt() {
  24. return ct;
  25. }
  26. public void setCt(Class<?> ct) {
  27. this.ct = ct;
  28. }
  29. @Override
  30. public void serialize(Object obj, byte[] bytes) {
  31. Kryo kryo = getKryo();
  32. Output output = getOutput(bytes);
  33. kryo.writeObjectOrNull(output, obj, obj.getClass());
  34. output.flush();
  35. }
  36. @Override
  37. public void serialize(Object obj, byte[] bytes, int offset, int count) {
  38. Kryo kryo = getKryo();
  39. Output output = getOutput(bytes, offset, count);
  40. kryo.writeObjectOrNull(output, obj, obj.getClass());
  41. output.flush();
  42. }
  43. /**
  44. * 獲取kryo
  45. *
  46. * @param t
  47. * @return
  48. */
  49. private Kryo getKryo() {
  50. return kryoLocal.get();
  51. }
  52. /**
  53. * 獲取Output並設置初始數組
  54. *
  55. * @param bytes
  56. * @return
  57. */
  58. private Output getOutput(byte[] bytes) {
  59. Output output = null;
  60. if ((output = outputLocal.get()) == null) {
  61. output = new Output();
  62. outputLocal.set(output);
  63. }
  64. if (bytes != null) {
  65. output.setBuffer(bytes);
  66. }
  67. return output;
  68. }
  69. /**
  70. * 獲取Output
  71. *
  72. * @param bytes
  73. * @return
  74. */
  75. private Output getOutput(byte[] bytes, int offset, int count) {
  76. Output output = null;
  77. if ((output = outputLocal.get()) == null) {
  78. output = new Output();
  79. outputLocal.set(output);
  80. }
  81. if (bytes != null) {
  82. output.writeBytes(bytes, offset, count);
  83. }
  84. return output;
  85. }
  86. /**
  87. * 獲取Input
  88. *
  89. * @param bytes
  90. * @param offset
  91. * @param count
  92. * @return
  93. */
  94. private Input getInput(byte[] bytes, int offset, int count) {
  95. Input input = null;
  96. if ((input = inputLocal.get()) == null) {
  97. input = new Input();
  98. inputLocal.set(input);
  99. }
  100. if (bytes != null) {
  101. input.setBuffer(bytes, offset, count);
  102. }
  103. return input;
  104. }
  105. @SuppressWarnings( "unchecked")
  106. @Override
  107. public <T> T deserialize(byte[] bytes, int offset, int count) {
  108. Kryo kryo = getKryo();
  109. Input input = getInput(bytes, offset, count);
  110. return (T) kryo.readObjectOrNull(input, ct);
  111. }
  112. @Override
  113. public <T> T deserialize(byte[] bytes) {
  114. return deserialize(bytes, 0, bytes.length);
  115. }

測試一下kryo的序列化和反序列化

為什么使用納秒,而不用毫秒?與java原生的序列化反序列化要耗時幾毫秒不同,kryo序列化和反序列化太快了,單個對象的序列化反序列化速度都在0.0x毫秒左右(如果電腦性能更好的話,會更快)


   
   
  
  
          
  1. Serializer ser = new kryoSerializer(Msg.class);
  2. for ( int i = 0; i < 10; i++) {
  3. Msg msg = new Msg();
  4. msg.setVersion_flag( new byte[] { 1, 2, 3 });
  5. msg.setCrc_code(( short) 1);
  6. msg.setMsg_body( new byte[] { 123, 123, 123, 43, 42, 1, 12, 45, 57, 98 });
  7. byte[] bytes = new byte[ 300];
  8. long start = System.nanoTime();
  9. ser.serialize(msg, bytes);
  10. System.err.println( "序列化耗時:" + (System.nanoTime() - start));
  11. System.out.println(msg);
  12. System.out.println(Arrays.toString(bytes));
  13. Msg newmsg = null;
  14. start = System.nanoTime();
  15. newmsg = ser.deserialize(bytes);
  16. System.err.println( "反序列化耗時:" + (System.nanoTime() - start));
  17. System.out.println(newmsg);
  18. }
----end----











免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM