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