分析C 二進位制序列化詬病所在,並解決問題(二)

2021-10-19 08:58:33 字數 3897 閱讀 7168

上節說到關於序列化,我們或許已經發現了其詬病,其實說到底二進位制序列化並沒有問題,只是我們的編碼習慣不正確而已,那麼接下來讓我們來徹底優化二進位制序列化,binaryformatter走起。。。。

上節最後,我們對**進行了簡單優化,可優化因素就是將stream宣告成了全域性變數,減少了stream的擴建和釋放,測試結果比較明顯,但是依然存在大量gc。

private

static

byte

serialize

(object obj)

}

static

memorystream stream =

newmemorystream()

;private

static

byte

serialize

(object obj)

從上節簡單分析可知,對序列化速度影響比較大的就是對於記憶體的操作,經過對stream的全域性宣告,結果有所改善,但是因為呼叫了toarray,最後還是會複製乙份記憶體,所以最好是能直接將流中的byte陣列直接返回,這樣基本就可以解決記憶體問題,理論可行,實踐開始!!

memorystream是c#預設的記憶體流,其中有個建構函式可以設定buffer可見,然後呼叫getbuffer()方法,返回流中的byte陣列,看起來可以試試看。

在這裡不僅要把stream宣告成全域性變數,還需要指定其byte陣列和可用大小。所以需要估計出序列化後的資料物件的大小,所以這裡指定150k byte。

static

memorystream stream =

newmemorystream

(new

byte

[1024

*150],

0,1024

*150

,true

,true);

private

static

byte

serialize

(object obj)

康康效果

可以看出,這個效果更加明顯,在未優化前,耗時39s,簡單優化後,耗時16s,而現在的優化僅僅6s,而且幾乎沒有gc,看起來這個優化完美無瑕,可是真的能在專案中使用嗎?

從**可以看出,我們是直接把stream的buffer直接匯出的,很明顯,這樣做有個致命缺點就是多執行緒併發問題。

我們假想一種情況,假如我們需要序列化乙個物件並通過網路傳輸,並且有兩個執行緒不定時並行操作,也就是說,兩個執行緒不定時序列化不同的資料物件,然後將結果在網路中傳輸。那麼就有可能發生:第乙個執行緒剛序列化完成乙個資料物件,然後拿到了stream的buffer,然後進行傳輸,當傳輸到一半的時候,另乙個執行緒剛好也執行序列化,那麼stream的資料就會被改變,而傳輸那邊的**片又不知道,就會發生資料錯亂的問題。說到這裡,相信小夥伴想到了執行緒同步,使用lock,但是稍加思索就會發現,基本上行不通。

例如:下列**,在序列化時使用lock,可以保證在serialize方法中線程同步,但是一旦退出serialize,則資料還是會被破環,傳送髒資料現象。

static

memorystream stream =

newmemorystream

(new

byte

[1024

*150],

0,1024

*150

,true

,true);

private

static

byte

serialize

(object obj)

}

再例如下**,在serialize呼叫後依然使用lock,可以保證退出serialize時依然執行緒同步,但是此時還需要把網路傳輸也在lock中執行。這樣看起來沒什麼問題,但是。。。。那這樣的話,多執行緒的意義是什麼呢?

console.

readkey()

;student student =

newstudent()

; student.name =

"張三"

; student.age =20;

student.address =

"中國"

; student.data =

newbyte

[1024

*100];

timespan timespan = timemeasurer.

run(()

=>

if(i %

10000==0

)}})

;

綜上所述,直接使用memorystream看起來不太行了,那既然memorystream不行,只能引出rrqmcore中的byteblock了,但是byteblock和bytepool是密不可分的,具體實現可以看源**。在這裡可以直接使用。

如下兩個**片,因為byteblock繼承自stream,所以可以直接參與流操作,在序列化時可以返回位元組,或者流本身,如果是流本身的話就完美解決了多執行緒併發問題,因為記憶體池是執行緒安全的,獲取的byteblock是清潔的,等資料處理完成後,直接呼叫dispose就可以了。

/// 

/// 二進位制序列化物件

///

///

/// 返回流中的buffer,非執行緒安全

public

byte

binaryserializetobytes

(object obj)

///

/// 二進位制序列化物件

///

///

///

public

byteblock

binaryserializetobyteblock

(object obj)

當然在rrqmcore中已經封裝了高效能的二進位制及xml序列化器。

如下圖,封裝的靜態方法均是常規方法,高效能序列化器必須使用類物件。

康康效果

console.

readkey()

;student student =

newstudent()

; student.name =

"張三"

; student.age =20;

student.address =

"中國"

; student.data =

newbyte

[1024

*100];

serializeconvert serializeconvert = serializeconvert.

creatserializeconvert

(1024

*150);

timespan timespan = timemeasurer.

run(()

=>}}

);console.

writeline

(timespan)

; console.

readkey()

;

物件序列化 二進位制序列化

物件序列化是將物件 比如類物件 轉換為二進位制資料 位元組流 反序列化是將二進位制資料還原為物件,和序列化沒有關係.關鍵字 binaryformatter 序列化 反序列化是為了保持物件的永續性.方便我們的儲存和資訊的交換.1.要序列化的物件必須比較為 serializable 2.如果有父類,該型...

二進位制序列化與XML序列化

序列化是將物件狀態轉換為可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換為物件。這兩個過程結合起來,就使得資料能夠被輕鬆地儲存和傳輸。net 框架提供兩種序列化技術 二進位制序列化保持型別保真度,這對於在應用程式的不同呼叫之間保留物件的狀態很有用。例如,通過將物件序列化到剪貼簿,可在不...

示例 二進位制序列化委託

用途 將委託序列化成二進位制,一般用於遠端呼叫方法 示例 1 單元測試 testmethod public void testserializabledelegate s 呼叫原委託 string xmls s.serializebinary myactionact xmls.serializede...