[開源]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

 

 

 

謝謝. 

 

 

/p


免責聲明!

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



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