国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - 編程技術(shù) - 用數(shù)據(jù)說話,序列化框架測評報告

用數(shù)據(jù)說話,序列化框架測評報告

2022-03-02 22:13愛笑的架構(gòu)師雷小帥 編程技術(shù)

今天選擇幾款市面上常用的序列化框架進行測試對比,幫助開發(fā)團隊搞清楚不同場景該采用哪種序列化框架。

序列化是我們在日常開發(fā)中經(jīng)常會使用到的技術(shù),比如需要將內(nèi)存對象持久化存儲、需要將對象通過網(wǎng)絡(luò)傳輸?shù)竭h端。目前市面上序列化框架非常多,開發(fā)團隊在進行技術(shù)選型時通常難以抉擇,甚至會踩坑。

今天選擇幾款市面上常用的序列化框架進行測試對比,幫助開發(fā)團隊搞清楚不同場景該采用哪種序列化框架。

測試對比的框架有四款:

JDK原生、fastjson、Kryo、Protobuf

接下來會從以下這四個方面給出詳細的測試對比結(jié)果:

(1)是否通用:是否支持跨語言、跨平臺;

(2)是否容易使用:是否編譯使用和調(diào)試;

(3)性能好不好:序列化性能主要包括時間開銷和空間開銷,時間開銷是指序列化和反序列化對象所耗費的時間,空間開銷是指序列化生成數(shù)據(jù)大小;

(4)可擴展強不強:隨著業(yè)務(wù)發(fā)展,傳輸?shù)臉I(yè)務(wù)對象可能會發(fā)生變化,比如說新增字段,這個時候就要看所選用的序列化框架是否有良好的擴展性;

框架1:JDK原生

是否通用?

JDK 原生是 Java 自帶的序列化框架,與 Java 語言是強綁定的,通過 JDK 將對象序列化后是無法通過其他語言進行返序列化的,所以它的通用性比較差。

是否容易使用?

一個類實現(xiàn)了java.io.Serializable序列化接口就代表這個類的對象可以被序列化,否則就會報錯。

簡單認識一下Serializable這個類,通過看源碼我們知道Serializable僅僅是一個空接口,沒有定義任何方法。

public interface Serializable { } 

這說明Serializable僅僅是一個標識的作用,用來告訴 JVM 這個對象可以被序列化。

想真正完成對象序列化和反序列化還得借助 IO 核心操作類:ObjectOutputStream和ObjectInputStream。

  /**  * 序列化  *  * @param obj 待序列化對象  * @return 二進制字節(jié)數(shù)組  * @throws IOException  */ public static byte[] serialize(Object obj) throws IOException { // 字節(jié)輸出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 將對象序列化為二進制字節(jié)流
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(obj); // 獲取二進制字節(jié)數(shù)組
        byte[] bytes = byteArrayOutputStream.toByteArray(); // 關(guān)閉流
        objectOutputStream.close(); byteArrayOutputStream.close(); return bytes; } 

ObjectInputStream類的readObject()方法用于從 IO 流中讀取對象,完成對象反序列化:

  /**  * 反序列化  *  * @param bytes 待反序列化二進制字節(jié)數(shù)組  * @param  反序列對象類型  * @return 反序列對象  * @throws IOException  * @throws ClassNotFoundException  */ public static <T> T deSerialize(byte[] bytes) throws IOException, ClassNotFoundException { // 字節(jié)輸入流
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); // 將二進制字節(jié)流反序列化為對象
        final ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); final T object = (T) objectInputStream.readObject(); // 關(guān)閉流
        objectInputStream.close(); byteArrayInputStream.close(); return object; } 

從上面的代碼可以看出,JDK 原生框架使用起來還是有點麻煩的,首先要求對象必須實現(xiàn)java.io.Serializable接口,其次需要借助 IO 流操作來完成序列化和反序列化。與市面上其他開源框架比起來,上面的代碼寫起來非常生硬。

一句話總結(jié):JDK 原生框架易用性稍差。

性能好不好?

(1)序列化體積測試

為了方便測試對比,我定義了一個普通 java 類,后面其他框架的測試基本上也是用這個類:

public class UserDTO implements Serializable { private String name; private String wechatPub; private String job; …… } 

將 UserDTO 類進行實例化

UserDTO userDTO = new UserDTO(); userDTO.setName("雷小帥"); userDTO.setWechatPub("微信公眾號:愛笑的架構(gòu)師"); userDTO.setJob("優(yōu)秀碼農(nóng)"); 

序列化和反序列化測試:

System.out.println("--- 1. jdk 原生測試 ---"); byte[] bytes = JDKSerializationUtil.serialize(userDTO); System.out.println("序列化成功:" + Arrays.toString(bytes)); System.out.println("byte size=" + bytes.length); UserDTO userDTO1 = JDKSerializationUtil.deSerialize(bytes); System.out.println("反序列化成功:" + userDTO1); 

打印出來的結(jié)果:

--- 1. jdk 原生測試 --- 序列化成功:[-84, -19, 0, 5, 115, 114, 0, 39, ……
byte size=182 反序列化成功:UserDTO[name='雷小帥', wechatPub='微信公眾號:愛笑的架構(gòu)師', job='優(yōu)秀碼農(nóng)'] 

一個 UserDTO 序列化完之后是 182 個字節(jié),待會對比其他框架就知道,這個水平太差了,Java 原生是自帶的序列化工具,親兒子也不給力啊。

(2)序列化速度測試

接下來我們再測試一下序列化和反序列化的速度,總共循環(huán) 100 萬次:

  • JDK 序列化耗時:2314 毫秒
  • JDK 反序列化耗時:4170 毫秒

這個成績怎么樣,后面揭曉。

可擴展強不強?

JDK 原生序列化工具通過在類中定義 serialVersionUID 常量來控制版本:

private static final long serialVersionUID = 7982581299541067770L; 

上面這個serialVersionUID是通過 IDEA 工具自動生成的長整形。其實你也可以不用聲明這個值,JDK 會根據(jù) hash 算法自動生成一個。

如果序列化的時候版本號是當前這個值,反序列化前你將值改變了,那么反序列化的時候就會報錯,提示 ID 不一致。

假如需要在 UserDTO 這個類再加一個字段,那如何支持擴展呢?

你可以改變一下serialVersionUID值就可以了。

框架2:fastjson

是否通用?

fastjson 是阿里巴巴出品的一款序列化框架,可以將對象序列化為 JSON 字符串,類似的框架還有 jackson, gson 等。

由于 JSON 是與語言和平臺無關(guān),因此它的通用性還是很好的。

是否容易使用?

UserDTO 類不需要實現(xiàn) Serializable 接口,也不需要加 serialVersionUID 版本號,使用起來非常簡單。

將一個對象序列化為 json 字符串:

com.alibaba.fastjson.JSON.toJSONString(obj); 

將 json 字符串反序列化為指定類型:

com.alibaba.fastjson.JSON.parseObject(jsonString, clazz); 

另外 fastjson 框架還提供了很多注解,可以在 UserDTO 類進行配置,實現(xiàn)一些定制化的功能需求。

性能好不好?

(1)序列化體積測試

跟 JDK 原生框架一樣,假設(shè)我們已經(jīng)實例化好了一個UserDTO 對象,分別進行序列化和反序列化測試:

System.out.println("--- 2. fastjson 測試 ---"); String jsonString = FastjsonSerializationUtil.serialize(userDTO); System.out.println("序列化成功: " + jsonString); System.out.println("byte size=" + jsonString.length()); UserDTO userDTO2 = FastjsonSerializationUtil.deSerialize(jsonString, UserDTO.class); System.out.println("反序列化成功:" + userDTO2); 

上面的代碼是將序列化和反序列化代碼封裝到了一個工具類中。運行輸出結(jié)果:

--- 2. fastjson 測試 --- 序列化成功: {"job":"優(yōu)秀碼農(nóng)","name":"雷小帥","wechatPub":"微信公眾號:愛笑的架構(gòu)師"} byte size=54 反序列化成功:UserDTO[name='雷小帥', wechatPub='微信公眾號:愛笑的架構(gòu)師', job='優(yōu)秀碼農(nóng)'] 

可以看到序列化之后有 54 個字節(jié),而上面 JDK 原生框架是182 個字節(jié),對比下來發(fā)現(xiàn) fastjson 確實比 JDK 原生框架強了不少,親兒子真不行。

(2)序列化速度測試

序列化體積測試完了之后,我們再測試一下序列化和反序列化速度,經(jīng)過漫長的等待,循環(huán)跑了 100 萬次之后實測結(jié)果如下:

  • fastjson 序列化耗時:287 毫秒
  • fastjson 反序列化耗時:365 毫秒

這個結(jié)果簡直,人如其名啊,真快~ 你看看隔壁 JDK 原生框架的速度,慘不忍睹,哎……

可擴展強不強?

fastjson 沒有版本控制機制,如果對類進行修改,比如新增熟悉字段,反序列時可以進行配置,忽略不認識的熟悉字段就可以正常進行反序列化。

所以說 fastjson 的擴展性還是很靈活的。

框架3:Kryo

是否通用?

Kryo 是一個快速高效的二進制序列化框架,號稱是 Java 領(lǐng)域最快的。它的特點是序列化速度快、體積小、接口易使用。

Kryo支持自動深/淺拷貝,它是直接通過對象->對象的深度拷貝,而不是對象->字節(jié)->對象的過程。

關(guān)于 Kryo 更多的介紹可以去 Github 查看:

https://github.com/EsotericSoftware/kryo

關(guān)于通用性,Kryo 是一款針對 Java 語言開發(fā)的框架,基本很難跨語言使用,因此通用性比較差。

是否容易使用?

先引入 Kryo 依賴:

<dependency> <groupId>com.esotericsoftwaregroupId> <artifactId>kryoartifactId> <version>5.3.0version> dependency> 

Kryo 提供的 API 非常簡潔,Output 類封裝了輸出流操作,使用 writeObject 方法將對象寫入 output 輸出流程即可完成二進制序列化過程。

下面代碼封裝了一個簡單的工具方法:

/**  * 序列化  *  * @param obj  待序列化對象  * @param kryo kryo 對象  * @return 字節(jié)數(shù)組  */ public static byte[] serialize(Object obj, Kryo kryo) { Output output = new Output(1024); kryo.writeObject(output, obj); output.flush(); return output.toBytes(); } 

Kryo 反序列化也非常簡單,Input 封裝了輸入流操作,通過 readObject 方法從輸入流讀取二進制反序列化成對象。

/**  * 反序列化  *  * @param bytes 待反序列化二進制字節(jié)數(shù)組  * @param    反序列對象類型  * @return 反序列對象  */ public static <T> T deSerialize(byte[] bytes, Class<T> clazz, Kryo kryo) { Input input = new Input(bytes); return kryo.readObject(input, clazz); } 

另外 Kryo 提供了豐富的配置項,可以在創(chuàng)建 Kryo 對象時進行配置。

總體而言,Kryo 使用起來還是非常簡單的,接口易用性也是非常不錯的。

性能好不好?

(1)序列化體積測試

Kryo 框架與其他框架不同,在實例化的時候可以選擇提前注冊類,這樣序列化反序列化的速度會更快,當然也可以選擇不注冊。

System.out.println("--- 3. kryo 測試 ---"); Kryo kryo = new Kryo(); kryo.setRegistrationRequired(false); // kryo.register(UserDTO.class); byte[] kryoBytes = KryoSerializationUtil.serialize(userDTO, kryo); System.out.println("序列化成功:" + Arrays.toString(kryoBytes)); System.out.println("byte size=" + kryoBytes.length); UserDTO userDTO3 = KryoSerializationUtil.deSerialize(kryoBytes, UserDTO.class, kryo); System.out.println("反序列化成功:" + userDTO3); 

運行結(jié)果:

序列化成功:[-123, -28, -68, -104, -25, ……] byte size=60 反序列化成功:UserDTO[name='雷小帥', wechatPub='微信公眾號:愛笑的架構(gòu)師', job='優(yōu)秀碼農(nóng)'] 

從結(jié)果來看,序列化后總共是 60 字節(jié)。

(2)序列化速度測試

序列化體積測試完了之后,我們再測試一下序列化和反序列化速度,經(jīng)過漫長的等待,循環(huán)跑了 100 萬次之后實測結(jié)果如下:

  • kryo 序列化耗時:295 毫秒
  • kryo 反序列化耗時:211 毫秒

這個成績還不錯。

可擴展強不強?

Kryo默認序列化器 FiledSerializer 是不支持字段擴展的,如果想要使用擴展序列化器則需要配置其它默認序列化器。

框架4:Protobuf

是否通用?

Protobuf 是谷歌開源的一款二進制序列化框架。

Protobuf 要求先寫schema描述文件,然后通過編譯器編譯成具體的編程語言(Java、C++、Go 等),因此它是一種語言中立、跨平臺的框架,通用性非常好。

是否容易使用?

先編寫 schema 文件,定義了一個 User 類,擁有三個屬性字段:

syntax = "proto3"; option java_package = "com.example.demo2.serialization.protobuf"; message User { string name = 1; string wechatPub = 2; string job = 3; } 

接著在電腦上安裝好 Protobuf 編譯工具,執(zhí)行編譯命令:

protoc --java_out=./  user-message.proto 

編譯成功后會生成一個 UserMessage 類。

UserMessage 類包含了很多內(nèi)容:

首先有一個 Builder 內(nèi)部類,可以用于實例化對象;

另外還提供了toByteArray(),可以很方便將對象序列化為二進制字節(jié)數(shù)組;提供了parseFrom()方法可以將對象反序列化為對象。

在接口使用上非常簡單,開箱即用。

性能好不好?

(1)序列化體積測試

使用上面生成的UserMessage類創(chuàng)建一個對象,然后再進行序列化和反序列化測試:

System.out.println("--- 4. protobuf 測試 ---"); UserMessage.User user = UserMessage.User.newBuilder() .setName("雷小帥") .setWechatPub("微信公眾號:愛笑的架構(gòu)師") .setJob("優(yōu)秀碼農(nóng)") .build(); final byte[] protoBufBytes = user.toByteArray(); System.out.println("序列化成功:" + Arrays.toString(protoBufBytes)); System.out.println("byte size=" + protoBufBytes.length); final UserMessage.User user1 = UserMessage.User.parseFrom(protoBufBytes); System.out.println("反序列化成功:" + user1); 

運行結(jié)果:

序列化成功:[-123, -28, -68, -104, -25, ……] byte size=63 反序列化成功:UserDTO[name='雷小帥', wechatPub='微信公眾號:愛笑的架構(gòu)師', job='優(yōu)秀碼農(nóng)'] 

序列化后是 63 字節(jié),比 Kryo 稍微多一點點,有點吃驚。

(2)序列化速度測試

序列化體積測試完了之后,我們再測試一下序列化和反序列化速度,經(jīng)過漫長的等待,循環(huán)跑了 100 萬次之后實測結(jié)果如下:

  • protobuf 序列化耗時:93 毫秒
  • protobuf 反序列化耗時:341 毫秒

序列化速度很強,但是反序列化為什么慢這么多?

可擴展強不強?

可擴展性是 Protobuf 設(shè)計目標之一,我們可以很方便進行字段增刪,新舊協(xié)議都可以進行解析。

總結(jié):

本文對常用的框架進行了測試對比,通過觀察 是否通用、是否容易使用、性能好不好、可擴展強不強 這四種維度,我們發(fā)現(xiàn)它們各有優(yōu)劣,大家在進行技術(shù)選型時一定要慎重。

最后針對性能測試這一塊,簡單總結(jié)一下,給每種框架排個序。

(1)序列化體積

fastjson 54 bytes < Kryo 60 bytes < Protobuf 63 bytes < Java 原生 182 bytes

體積越小,傳輸效率越高,性能更優(yōu)。Java 親兒子真慘!

(2)序列化速度

protobuf 93 毫秒 < fastjson 289 毫秒 < kryo 295 毫秒 < Java 原生 2247 毫秒

Protobuf 真牛逼,王者!Java 親兒子繼續(xù)輸~

(3)反序列化速度

kryo 211 毫秒 < protobuf 341 毫秒 < fastjson 396 毫秒 < Java 原生 4061 毫秒

Kryo 成績比較穩(wěn)定,序列化和反序列用時接近。Java 親兒子輸麻了!

原文地址:https://mp.weixin.qq.com/s/Z9ahavCHPxQRfBzjuVJwSg

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 色婷婷亚洲一区二区三区 | av网站免费看 | 久久男人的天堂 | 91精品视频一区 | 国产欧美日韩精品一区 | 久久久久久久久久亚洲 | 国产片在线观看 | 国产一区二区视频在线观看 | 黄色片免费在线看 | 亚洲精品九九 | www日韩| 国产免费av网站 | 亚洲一区高清 | 黄色三级免费片 | 在线精品日韩 | 日韩电影免费在线观看 | 欧美啪啪一区二区 | 精品黄色在线 | 黄色av网站在线观看 | 可以在线观看的av网站 | 日韩大片免费看 | 日韩一区中文 | 中文字幕精品视频 | av中文在线| 国产免费黄色 | 欧美在线视频一区 | 国产亚洲综合一区二区 | 国产一区二区三区四 | 日韩精品一区二区三区免费视频 | 精品一区二区三区免费毛片 | 高清日韩av | 欧美麻豆 | 国内精品视频一区 | 日韩在线免费观看视频 | 伊人中文字幕 | 在线永久免费观看黄网站 | 日韩在线成人 | 国产精品久久久久久久9999 | 日韩精品在线观看免费 | 中文字幕在线观看 | 91精品久久久久久久91蜜桃 |