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

转载 2013年12月04日 15:08:30

在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

3、CompactFormatterPlus 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

5、Yefan binary serialize

Data Length    : 113 byte

Serialize Time   : 8 ms

Deserialize Time : 8 ms 

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

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

Class Test1

{

   Public int v1=0;

   Public Object o=null;

}

Test1 t=new Test1();

t.o=t;   //为自身

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

Enum Test:byte  {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] { 012 };
        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
    }
}

极其精简的PHP框架WJW

WJW框架建议在每一次请求中都尽量少得加载文件、尽量短的代码执行路径,因为开发者在组织代码结构时也需要往这个方向靠拢,才能开发出更加极速高效的系统。 框架仅支持PDO连接数据库,不做多种数据库的支持,...
  • hzai20089
  • hzai20089
  • 2017年06月21日 11:28
  • 2660

ffmpeg 库精简

./configure --enable-cross-compile --target-os=linux --cross-prefix=arm-linux- --cc=arm-linux-gcc --...
  • huangqbio2
  • huangqbio2
  • 2014年05月12日 15:28
  • 855

ffmpeg精简

本文仅是个人编译脚本记录,有多出错误,仅供参考 编译32位库测试可通过,64位库使用r10e可编译通过arm64,x86_64,但是mips64编译有错,后序更改. 注: 1、android、交叉编译...
  • fatiao101
  • fatiao101
  • 2016年01月11日 23:27
  • 1550

终极精简编译Qt5,精简OpenGL,QMainWindow,ICU,WebKit等

Qt5完整编译太大了,项目里有些东西根本不需要,所以动手精简编译。 工具:VC2013,Qt5.2.1(5.3,5.4)均可。 首先 先精简ICU,使用ICU4.6版本,高版本只会占用更多空间 ...
  • hats8888
  • hats8888
  • 2015年06月05日 16:29
  • 2979

超精简的json输出类

package com.kievnsoft.json; import java.io.IOException; import java.lang.reflect.Array; import ja...
  • kivenlee
  • kivenlee
  • 2011年03月30日 09:48
  • 1096

Unity Notes之发布包精简

好久没有更新博客了。从客记
  • BugRunner
  • BugRunner
  • 2014年07月26日 18:35
  • 3911

mini webkit (精简版 webkit)即将开源

(从我的百度博客搬到csdn来,现在百度博客已经没落了,唉。) 为什么需要mini版本webkit: 传统的windows界面开发,非常繁琐,大家都希望能用HTML来开发界面。目前市面上可选的几种...
  • weolar
  • weolar
  • 2013年12月22日 20:27
  • 5925

精简版ffmpeg编译脚本

#!/bin/sh build_one () { ./configure --target-os=linux \     --enable-cross-compile \  ...
  • mianhuantang848989
  • mianhuantang848989
  • 2017年03月08日 20:38
  • 877

Android客户端.So 精简策略

*/1..So 理论基础首先介绍一下 目前所有手机上 .So 的指令集Android系统目前支持以下七种不同的CPU架构,每一种都关联着一个相应的ABI。而架构上对应的指令集是以下几种 Intel 6...
  • ccj659
  • ccj659
  • 2017年10月29日 21:04
  • 363

Android平台ROM的定制及精简教程

速度与华丽,你喜欢那个。是不是想要一个又够速度又华丽的ROM呢?我是一个追求新鲜的人,对于手机的ROM,我又追求稳定、精简、美观、省电。现在 ROM 有很多,最新的有第三方Android 4.03版本...
  • gjy_it
  • gjy_it
  • 2017年01月21日 09:41
  • 3118
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自行开发高效精简的二进制序列化库(支持精简框架集)
举报原因:
原因补充:

(最多只允许输入30个字)