[开源]KJFramework.Message 高性能二进制消息框架 - 非托管优化

框架的介绍: 


1. 已经完成了对于消息内部类型的支持(.NET类型)
2. 对于智能对象内部的“智能对象”提供支持。 支持迭代元数据转换。


[说明:]
KJFramework框架中内置了一套,可以将网络传输实体自动转换为二进制元数据的能力框架。
使用此框架,将使得用户不在关心底层传输时对于二进制编码/解码的繁琐过程,解放程序员的脑力劳动。
目前此内置框架被初步定义在命名空间:KJFramework.Messages内,拥有独立Assembly.
对于智能二进制消息框架, 内部提供了对于诸多类型的支持,甚至可以用于在不编写序列化代码的情况下,
将一个网络传输实体转换为二进制操作。
这一切的操作,都全部由内部框架完成,通过简单的属性标签,就可以实现很强大的转换功能。
目前智能二进制消息框架中,仍保留了内部扩展能力,日后扩展后,将会通过配置文件来增强配置能力。

 

新优化

不得不说的是,这是一次非常重要的更新。这次的更新,标志着KJFramework.Message
序列化框架已经脱胎换骨了。经过我们的思考,在以往的序列化/反序列化中,经常困扰我们的
性能问题,无外乎就2个。 那就是“GC的压力”以及“内存COPY很频繁”的问题。
在本次的更新中,我们将为您解决上述的2个问题。 好吧,让我们来谈谈本次更新。

1. 引入了非托管内存池,为对象序列化提供了直接的优化,这样的做法,使得高频度的对象序列化,
   所造成的GC压力直接降为最低。
      在以往的测试中,我们发现,由于高频度的序列化对象所造成的GC压力越来越大,这直接的原因,那就是
  我们无法做到预测对象的大小,以便于直接开辟出一块足够的空间来完成“无需字节数组拼接”的序列化操作。
  但是,慢慢的,这一切将会拖慢您的应用程序,因为对象的序列化已经占用了大多数的GC时间,这是一个
  很糟糕的情况,所以,本次的更新将会为您解决这个问题。
2. 解决了99%的拆装箱内存COPY问题。
      好吧,让我们来谈论一下这个问题,在以往的设计中,无论可序列化对象的字段是什么类型,我们都会将这个字段
  的值转变为object然后再去处理,当时,KJFramework.Message的设计使得我们无法去避免这个问题。这是个拥有
  坏味道的设计,不是吗? 由于高频度的对象序列化,所产生的大量拆、装箱情况,已经引起了我们足够的重视。
  在本次的设计中,我们已经为您带来针对这个问题的最终解决方案,那就是 - 避免拆、装箱的发生。
      我们特地为每一个可序列化字段设计了基于MSIL的动态基础单元,这是个重点,这个MSIL动态基础单元的出现,
  直接避免了任何的拆,装箱行为。然后,仅仅是这样还是不够的,于是,我们又将所有的字段序列化操作滞后到
  每一个单独的类型处理器中,我们相信,只有每一个处理器中,才知道它们自己要处理的是什么类型,所以,当滞后的
  序列化操作加上一个动态的MSIL基础单元,这个问题也就迎刃而解了,这一切都是那么的完美,那么的优雅。
      我们还为IIntellectTypeProcessor设计了新的序列化重载方法,我们建议,所有编写或者基于原有老接口的使用者,都去实现
  这个新的重载操作,我们相信,您将会喜欢上这个新方法的。
  最后,我们再来说一下,为什么这次所带来的解决方案只解决了99%的拆、装箱问题,那是因为,我们的框架还要支持
  可空值类型,它的出现,会为我们带来一部分的拆、装箱损耗。
3. 完整的类型大小定义方案
       在KJFramework.Message原来的设计中,每一个类型的序列化或者反序列化都是在代码中直接写死了该类型所占用的字节数,
   众所周知,这种行为是非常不好的,那么本次的更新中,这个问题我们也给出了解决方案。一个新的类型"Size"出现了,
  他的出现解决了上述问题。 一切的类型所占用字节数都是由sizeof运算符所计算出的。
4. 规范了异常类型
       在KJFramework.Message原来的设计中,所抛出的只有一些.NET的基础异常类型,我们一直都期望,能定义出符合规范的自定义异常类型,
   以及规格化的异常输出信息。当然,这一点在本次更新中也有所体现,比如,我们设计了一个新的异常类型"PropertyNullValueException"以及
   一个新的异常信息规格化类"ExceptionMessage"。
5. 创建了一套规范化的非托管操作API
       由于在本次的更新中,我们引入了非托管内存池的机制,这也就不得不牵扯到操作非托管内存的API。请不用担心,我们为这套系统设计了一套
   非常易用的非托管内存操作API,利用这套API,我们相信,当您使用我们的KJFramework.Message做二次开发时,将变得更加得心应手。
6. 全类型支持的大规模元素数组序列化优化
       在上一个版本中,我们公布出了很少类型的大规模元素数组序列化优化方案,在本次中,我们的系统已经支持了全部类型的数组优化方案!这是一个
   令人激动人心的时刻,当您的业务中,需要大量数组元素参与网络传输的时候,您才会发现本次更新的重要性。
7. 更详细的单元测试
   在本次版本的更新中,我们加入了更多的单元测试用例,来更加完整的测试我们的系统。
8. 修改了系统中存在的一些BUG
9. 修整了整体系统代码,让这个框架代码变得更加整洁

 

与此框架类似的通用组件:

ProtoBuffer - Google.

 

此框架的应用:

可以将此框架应用到网络对象的传输上,也就是说,当我们做一个分布式系统的时候,

只需要使用此框架,我们将无需再关心底层消息对象的序列化和反序列化细节,这一切的

工作将会由框架内部来完成。

 

性能指标:

此框架的基于.NETFRAMEWORK 4.0开发

测试平台:

CPU: Intel(R)Xeon(R)CPU X5670 @2.93GHz @2.93GHz (2处理器) 

System: Windows Server 2008 R2 Enterprise 

定义: 复杂对象,内部包含了多个数组类型的成员,比如string[], int[],

          内部还嵌套了其余类。

*想看看在这里测试的复杂对象到底有多复杂吗?  附上测试类的代码

*在我们的测试中,使用的是下列代码中的TestObject. 从下列代码中可以看到,此类型拥有很多的数组,而且还包含了其他的子类型 

 

 

public class TestObject : IntellectObject
    {
        private TestObject1 _obj;
        [IntellectProperty(7)]
        public TestObject1 Obj
        {
            get { return _obj; }
            set { _obj = value; }
        }

        private int[] _mm;
        [IntellectProperty(0)]
        public int[] Mm
        {
            get { return _mm; }
            set { _mm = value; }
        }

        private TestObject1[] _pp;
        [IntellectProperty(27)]
        public TestObject1[] Pp
        {
            get { return _pp; }
            set { _pp = value; }
        }


        private String[] _uu;
        [IntellectProperty(28)]
        public String[] Uu
        {
            get { return _uu; }
            set { _uu = value; }
        }


        private TestObject2[] _nn;
        [IntellectProperty(30)]
        public TestObject2[] Nn
        {
            get { return _nn; }
            set { _nn = value; }
        }

        private String[] _jj;
        [IntellectProperty(26)]
        public String[] Jj
        {
            get { return _jj; }
            set { _jj = value; }
        }

        private int _wokao;
        [IntellectProperty(4)]
        public int Wokao
        {
            get { return _wokao; }
            set { _wokao = value; }
        }

        private int _wocao;
        [IntellectProperty(2)]
        public int Wocao
        {
            get { return _wocao; }
            set { _wocao = value; }
        }

        private string _woqunimade;
        [IntellectProperty(3)]
        public string Woqunimade
        {
            get { return _woqunimade; }
            set { _woqunimade = value; }
        }

        private byte[] _metadata;
        [IntellectProperty(13)]
        public byte[] Metadata
        {
            get { return _metadata; }
            set { _metadata = value; }
        }


        private byte _metadata1;
        [IntellectProperty(15)]
        public byte Metadata1
        {
            get { return _metadata1; }
            set { _metadata1 = value; }
        }

        private TestObject2 _obj2;
        [IntellectProperty(16)]
        public TestObject2 Obj2
        {
            get { return _obj2; }
            set { _obj2 = value; }
        }

        private DateTime _time;
        [IntellectProperty(100)]
        public DateTime Time
        {
            get { return _time; }
            set { _time = value; }
        }

    }



    public class TestObject1 : IntellectObject
    {
        private string _haha;
        [IntellectProperty(0)]
        public string Haha
        {
            get { return _haha; }
            set { _haha = value; }
        }

        private Colors _colors;
        [IntellectProperty(1)]
        public Colors Colors
        {
            get { return _colors; }
            set { _colors = value; }
        }
    }



    [Serializable]
    public class TestObject2 : IClassSerializeObject
    {
        private int _nice;
        public int Nice
        {
            get { return _nice; }
            set { _nice = value; }
        }
    }

 

 

 

 

 *请注意: 由于性能的提升, 我们在2012年02月28日更新了性能指标!

序列化复杂对象(DEBUG):

     .次数 100000: 1100(ms) *此值根据测试机器的配置不同而不同,仅供参考
     .Gen0回收次数: 30
     .Gen1回收次数: 12
     .Gen2回收次数: 1

反序列化复杂对象(DEBUG):

     .次数 100000: 863(ms) *此值根据测试机器的配置不同而不同,仅供参考
     .Gen0回收次数: 22
     .Gen1回收次数: 1
     .Gen2回收次数: 0



序列化复杂对象(RELEASE):

     .次数 100000: 950(ms) *此值根据测试机器的配置不同而不同,仅供参考
     .Gen0回收次数: 30
     .Gen1回收次数: 12
     .Gen2回收次数: 1

反序列化复杂对象(RELEASE):

     .次数 100000: 610(ms) *此值根据测试机器的配置不同而不同,仅供参考
     .Gen0回收次数: 22
     .Gen1回收次数: 1
     .Gen2回收次数: 0



*具体的测试截图, 请查看源代码Pictures目录下的图片.  

 

 

 

 

数据段格式图:

 

 

 

 

 

 

更高的自定义需求:  

  在此框架中,对于每一个可以序列化的类型(int, string .....等等),都会为其配备一个智能类型处理器(IIntellectTypeProcessor),在框架的使用中,这些处理器都是默认的,如果,您感觉还有更好的实现能够加速

当前的序列化或者反序列化流程,那么,您可以在您的系统初始化的时候,使用自己的智能类型处理器来替换系统

现有的。 这样,就达到了可自定义类型序列化和反序列化的标准和算法 :)  当然,您也可以选择添加一个新的处理器。

  其次,在KJFramework.Message中,我们能看到,每一个可序列化的字段,都需要一个智能属性标记[IntellectPropery]

而每个这种标记都需要为序列化的字段提供一个唯一的数字序号,就比如:[IntellectProperty(0)] ,如果当您的自定义类型,需要为一个特殊的字段做特殊处理的时候,可以选择为一个特殊的编号字段来定制一个特殊的智能类型处理器。

比如,我们的登录消息,如果有一个字段用来存储密码,而我们恰巧需要为此字段进行MD5加密。

  那么,该怎么办呢?  当然,办法有很多种,我们可以选择先进行MD5的加密,然后再赋值,也可以选择如下的方式:

 

/*以下为代码示例*/
public class LogonMessage : IntellectObject
{
  [IntellectProperty(0)]
  public string UserName{get;set;}
  
   //可以看到,Password字段的序号为1. 
   //我们就可以单独添加一个字段处理器 来处理每一个消息实体内包含有序号1的字段
  [IntellectProperty(1)]
  public string Password{get;set;}
}

 

  *请不用担心,KJFramework.Message内部会对此操作做特殊的支持,好来完成您的特殊需求 :)

 

 

更专业的需求:

   现在我们已经为一个智能对象(IntellectObject)加入了描述自身的能力(New)。 也就是说,使用者随时随地

都可以通过如下调用 来得到当前对象的字符串形式描述信息。

   IntellectObject.ToString(); 

  当得到了一个对象的描述信息后,我们就能够很轻松的将其记录到日志文件中,这是不是很方便呢?

在日后,我们将会不停地更新这套框架,这也就意味着,会有越来越多的功能在以后会被加入,

如果您感兴趣,我们希望您能够持续关注。

 

附:

   此框架目前已经能够达到初步的商用层次,完全可以当做网络消息协议的序列化和反序列化转换层来使用,

  相信使用过GOOGLE的ProtoBuffer的朋友都应该明白了。我会一直更新此框架,如果您的项目中有此类需求,

  那么您可以选择尝试一下这套框架, 不会让您失望的 :)

 

   项目地址:http://message.codeplex.com/ 

   目前此项目已经发布了Release版本,您可以选择直接下载二进制文件使用,或者下载源代码 :)

   如果在使用此框架的途中,有任何问题,您也可以选择与我联系,我将提供最优的技术支持。

    QQ:250623008

    Email: Kevin.Jee@live.cn

 

 

 

谢谢. 

posted @ 2012-07-10 08:54  Kevin.Jee  阅读(1460)  评论(2编辑  收藏  举报