自行开发高效精简的二进制序列化库(支持精简框架集)

简介: 在06年开发基于Window CE的嵌入式组态软件时就曾遇到序列化问题,由于程序运行在Window CE平台,其上的.Net Compact Framework仅支持XML序列化,而XML序列化不仅序列化后的体积较大,而且执行时间较长(参见我以前写的文章:嵌入式组态环境升级及XML反序列化慢的困惑、如何加速XML反序列化(精简框架集2.0SP1,WinCE4.2))。

06年开发基于Window CE的嵌入式组态软件时就曾遇到序列化问题,由于程序运行在Window CE平台,其上的.Net Compact Framework仅支持XML序列化,而XML序列化不仅序列化后的体积较大,而且执行时间较长(参见我以前写的文章:嵌入式组态环境升级及XML反序列化慢的困惑如何加速XML反序列化(精简框架集2.0SP1,WinCE4.2))。

而当时支持.Net Compact Framework的二进制序列化就是CompactFormatter(参见黎波的文章: .NET Compact Framework 2.0 中使用序列化)了,由于是第三方所开发,功能上尚不完善,故没有选用。

前段时间看MSN Direct代码,发现使用.Net Micro Framework二进制序列化后的广播数据比较小,并且速度快。所以想办法把相关代码做了平台移植,可没有想到的是在.net micro Framework.Net Framework中都可以正常运行的代码,在.NET Compact Framework中竟然不能运行(主要是对Assembly操作的相关函数支持不够)。

由于目前在.Net Compact Framework开发的应用逐渐增多,并且最近也打算升级原先开发的嵌入式组态软件,经过再三考虑决定自行开发支持精简框架集的二进制序列化(说明:.Net Micro Framework平台上的二进制序列化,由于运行在ARM系列的CPU上,会考虑一些大小端的问题,所以多于一个byte的值变量都要进行特殊处理,速度相对较慢,不过.Net Micro Framework二进制序列化的优点是,支持bit序列化(bool变量按位存取,也可以为其它变量指定位数),所以它的序列化结果是最精简的)。

.Net Micro Framework二进制序列化代码做参考,所以自行开发一个支持精简框架集二进制序列化库,并不是一件特别繁杂和痛苦的事:-

 

在开发二进制序列化之前,对要完成的二进制序列化库,有以下几方面的考虑:

一、速度要快;

二、体积要小;

三、要支持自定义序列化;

针对第一点,故舍弃了.Net Micro Framework二进制序列化的bit序列化支持,并且精简了一些功能,比如仅支持原生数据类型的一维数组序列化,仅支持ArrayList,不支持泛型,此外不自行反射Assembly中的Type,和.Net Compact Framework XML序列化一样,需要开发者从外部传入Type列表;

针对第二点采用了很多.Net Micro Framework的二进制序列化思想,如序列化后的数据中不保存Type 的完整的名字,仅保存该名字的4个字节的哈希值,字符串的长度和数组长度用变长的1~4个字节的空间来保存,多个对象引用相同,仅保存首个对象等等;

而第三点主要和我开发的嵌入式组态功能相关,大量的图元派生于基类图元,而基类中的大量属性,在不同的图元中用到的都不同,如果一概而论全部序列化,则结果会比较大,而采用自定义序列化就能很好地解决这个问题。此外值得一提的是.Net Micro Framework二进制序列化和.Net Compact Framework XML序列化都不支持该功能。

 

用了我大约4天的时间,终于完成了.Net Compact Framework 二进制序列化的第一版V0.1,目前测试的结果还是令人满意的(以下结果是在windows平台下测试的,循环执行100次)。

1.Net Micro Framework binary serialize

Data Length    : 103 byte

Serialize Time   : 46 ms

Deserialize Time : 46 ms

2.Net Compact Framework xml serialize

Data Length    : 998 byte

Serialize Time   : 31545 ms

Deserialize Time : 34092 ms

3CompactFormatterPlus binary serialize

Data Length    : 1598 byte

Serialize Time   : 103 ms

Deserialize Time : 132 ms

4.Net Framework binary serialize

Data Length    : 828 byte

Serialize Time   : 18 ms

Deserialize Time : 17 ms

5Yefan binary serialize

Data Length    : 113 byte

Serialize Time   : 8 ms

Deserialize Time : 8 ms

 

     由以上可以看出,除了在体积上稍稍大于.Net Micro Framework的二进制序列化外,和其它序列化后的结果相比,几乎相差一个数量级,此外执行时间是最小的,并且其它相比,是几个数量级的差别。

在开发二进制序列化过程中发现,.Net Compact Framework xmlCompactFormatterPlus都不支持循环引用,如下面的类:

Class Test1

{

   Public int v1=0;

   Public Object o=null;

}

Test1 t=new Test1();

t.o=t;   //为自身

如果对t序列化,则.Net Compact Framework xmlCompactFormatterPlus都会出现异常,此外对CompactFormatterPlus,如果enum类型的基础类型不是默认的int型,也会抛出异常,如下面的枚举:

Enum Testbyte  {one ,two};

 

主要测试代码如下:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Collections; using System.IO; using System.Xml.Serialization; namespace CETest { public partial class frmTest : Form { public frmTest() { InitializeComponent(); } private void btnTest_Click(object sender, EventArgs e) { #region 类型定义 Type[] Types = new Type[] { typeof(TestClass), typeof(TestClass1), typeof(TestClass2), typeof(Color) }; TestClass t1 = new TestClass(); t1.v1 = 11; t1.v2 = 22; t1.v3 = "33"; t1.v4[1] = 44; t1.v5[0] = "55"; t1.v6 = TestClass.enumtest.enum2; t1.V7 = 77; t1.v8.v1 = 88; t1.v9 = new TestClass2(); t1.v9.v1 = 99; t1.v10 = t1.v9; //t1 循环引用 TestClass1 t11 = new TestClass1(); //t11.v2.Add(t1); //t1 循环引用 t11.v2.Add(3); t11.v2.Add(5); t11.v1_base = 123; TestClass2 t22 = new TestClass2(); t1.v11.Add(t11); t1.v11.Add(t22); t1.v11.Add(1); //t1.v12 = Color.Green; #endregion string strInfo = ""; Application.DoEvents(); long start = 0; double tk1 = 0, tk2 = 0; byte[] bytData = null; int Count = 1; //if (chkXML.Checked) { start = DateTime.Now.Ticks; for (int i = 0; i < Count; i++) { MemoryStream ms = new MemoryStream(); XmlSerializer xmls = new XmlSerializer(typeof(TestClass), Types); xmls.Serialize(ms, t1); bytData = ms.ToArray(); ms.Close(); } tk1 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds; start = DateTime.Now.Ticks; for (int i = 0; i < Count; i++) { MemoryStream ms = new MemoryStream(bytData); XmlSerializer xmls = new XmlSerializer(typeof(TestClass), Types); TestClass obj2 = (TestClass)xmls.Deserialize(ms); ms.Close(); } tk2 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds; strInfo += ShowInfo(".Net Compact Framework xml serialize", bytData.Length, tk1, tk2); } //if (chkCF.Checked) //{ // start = DateTime.Now.Ticks; // for (int i = 0; i < Count; i++) // { // MemoryStream ms = new MemoryStream(); // CompactFormatter.CompactFormatter cf = new CompactFormatter.CompactFormatter(); // cf.Serialize(ms, t1); // bytData = ms.ToArray(); // ms.Close(); // } // tk1 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds; // start = DateTime.Now.Ticks; // for (int i = 0; i < Count; i++) // { // MemoryStream ms = new MemoryStream(bytData); // CompactFormatter.CompactFormatter cf = new CompactFormatter.CompactFormatter(); // TestClass obj3 = (TestClass)cf.Deserialize(ms); // ms.Close(); // } // tk2 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds; // strInfo += ShowInfo("CompactFormatterPlus binary serialize", bytData.Length, tk1, tk2); //} //if (chkYFSoft.Checked) { start = DateTime.Now.Ticks; for (int i = 0; i < Count; i++) { MemoryStream ms = new MemoryStream(); YFSoft.BinaryFormatter bf2 = new YFSoft.BinaryFormatter(Types); bf2.Serialize(ms, t1); bytData = ms.ToArray(); ms.Close(); } tk1 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds; start = DateTime.Now.Ticks; for (int i = 0; i < Count; i++) { MemoryStream ms = new MemoryStream(bytData); YFSoft.BinaryFormatter bf2 = new YFSoft.BinaryFormatter(Types); TestClass obj4 = (TestClass)bf2.Deserialize(ms); ms.Close(); } tk2 = TimeSpan.FromTicks(DateTime.Now.Ticks - start).TotalMilliseconds; strInfo += ShowInfo("Yefan binary serialize", bytData.Length, tk1, tk2); } txtInfo.Text = strInfo; } private string ShowInfo(string title, int length, double milliseconds1, double milliseconds2) { string strInfo = ""; strInfo += title + "/r/n"; strInfo += "Data Length : " + length.ToString() + "/r/n"; strInfo += "Serialize Time : " + milliseconds1.ToString() + " ms/r/n"; strInfo += "Deserialize Time : " + milliseconds2.ToString() + " ms/r/n/r/n"; return strInfo; } } [Serializable] public class TestClassBase { public int v1_base = 111; public string v2_base = "222"; } [Serializable] public class TestClass1 : TestClassBase { public int v1 = 1; public ArrayList v2 = new ArrayList(); } [Serializable] public class TestClass2 { public byte v1 = 1; public string v2 = "2"; } [Serializable] public class TestClass // :YFSoft.ISerializable { public int v1 = 1; [NonSerialized] public long v2 = 2; public string v3 = "v3"; public int[] v4 = new int[3] { 0, 1, 2 }; public string[] v5 = new string[2] { "123", "456" }; public enum enumtest : int { enum0, enum1, enum2 }; //:byte public enumtest v6 = enumtest.enum1; private UInt16 v7; public UInt16 V7 { get { return v7; } set { v7 = value; } } public TestClass1 v8 = new TestClass1(); public TestClass2 v9 = null; // new TestClass2(); public object v10 = null; public ArrayList v11 = new ArrayList(); //public Color v12 = Color.Red; #region ISerializable 成员 //public void GetObjectData(YFSoft.SerializationInfo si) //{ // v1 = si.GetInt32(); //} //public void SetObjectData(YFSoft.SerializationInfo si) //{ // si.AddValue(v1); //} #endregion } }

 

下载地址:http://www.sky-walker.com.cn/yefan/YFSerializeTest.rar

相关文章
|
缓存 自然语言处理 分布式计算
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
Fury是一个基于JIT动态编译的多语言原生序列化框架,支持Java/Python/Golang/C++等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
|
5天前
|
JSON Java Linux
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
20 2
|
9月前
|
存储 编译器 文件存储
4.4 C++ Boost 数据集序列化库
Boost库提供了一组通用的数据序列化和反序列化库,包括archive、text_oarchive、text_iarchive、xml_oarchive、xml_iarchive等。可用于许多数据类型的持久化和传输。使用这些库,我们可以轻松地将各种数据类型序列化到文件或流中,并从文件或流中反序列化数据。
94 0
|
5月前
|
JSON API 网络架构
Python Web 开发: 解释 Django REST framework 的作用,以及如何定义序列化器(Serializer)?
Python Web 开发: 解释 Django REST framework 的作用,以及如何定义序列化器(Serializer)?
|
5月前
|
JSON Java Go
Go内置序列化库 - gob
Go内置序列化库 - gob
|
10月前
|
存储 JSON 数据格式
【Python标准库】Pickle库与序列化
【Python标准库】Pickle库与序列化
|
10月前
|
缓存 自然语言处理 Rust
比JDK最高快170倍,蚂蚁集团开源高性能多语言序列化框架Fury
Fury是一个基于JIT动态编译和零拷贝的多语言序列化框架,支持Java/Python/Golang/JavaScript/C++等语言,提供全自动的对象多语言/跨语言序列化能力,和相比JDK最高170倍的性能。经过多年蚂蚁核心场景的锤炼打磨,现已正式在Github对外开源:https://github.com/alipay/fury
2387 5
|
11月前
|
算法 Java 对象存储
序列化与反序列化——作为Java开发,应该避开这些坑
阅读本文,将带你了解几个问题: 1.序列化与反序列化的概念 2.子类实现Serializable接口,父类没有实现,子类可以序列化吗? 3.类中存在引用对象,这个类对象在什么情况下可以实现序列化? 4.同一个对象多次序列化之间有属性更新,前后的序列化有什么区别?
137 0
序列化与反序列化——作为Java开发,应该避开这些坑
|
12月前
|
JSON 数据格式 C++
Protobuf vs CBOR:新一代的二进制序列化格式
Protobuf vs CBOR:新一代的二进制序列化格式
605 0
Java开发——31.I/O流_处理流(对象流),对象的序列化机制
对象的序列化机制:允许把内存中的Java对象转换成和平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点(序列化);其它程序获取了这种二进制流,就可以恢复成原来的Java对象(反序列化)。
Java开发——31.I/O流_处理流(对象流),对象的序列化机制