2015-01-07 42 views
3

我正在使用TPL數據流塊來實現基於數據包的網絡協議。這個協議是固定的,不能被我改變。主要是小的,但很多數據包。在TPL數據流中使用DeflateStream和/或CryptoStream數據流TransformBlock

我有一個客戶端組件連接到服務器並讀取原始數據包。然後這些原始數據包將作爲MemoryStreams發佈到BufferBlock,然後在TransformBlock中根據數據包類型/ ID解碼爲數據包結構。

要發送數據包,此過程與另一鏈數據流塊反向。就我所知,所有這些都很有效。

問題是,這些數據包可能會或可能不會被壓縮,可能會或可能不會被加密,基於服務器響應。我會提出新的插圖中TransformBlocks(使用解壓縮爲例)解決這個問題:

static TransformBlock<Stream, Stream> CreateDecompressorBlock(ProtocolContext context) 
{ 
    return new TransformBlock<Stream, Stream>(stream => 
    { 
     if (!context.CompressionEnabled) return stream; 
     return new DeflateStream(stream, CompressionMode.Decompress); 
    } 
} 

然而,這在我看來就像是不正確的做法。據我瞭解,DeflateStream(和CryptoStream)在讀取數據時解碼數據。這意味着數據在我對數據包內容進行解碼時被解碼,而不是在TransformBlock本身內部進行解碼,其中只有包裝流被創建。這似乎會繞過數據流塊的優勢。

那麼另一種解決方案來我的心在那裏而不是返回DeflateStream/CryptoStream的,我讀通過它到另一個的MemoryStream:

static TransformBlock<Stream, Stream> CreateDecompressorBlock(ProtocolContext context) 
{ 
    return new TransformBlock<Stream, Stream>(stream => 
    { 
     if (!context.CompressionEnabled) return stream; 
     using (var deflate = new DeflateStream(stream, CompressionMode.Decompress)) 
     { 
      var ms = new MemoryStream(); 
      deflate.CopyTo(ms); 
      return ms; 
     } 
    } 
} 

現在,這似乎是浪費內存。

所以我的問題是,是否足以包裝流,讓稍後解碼數據包內容的TransformBlock完成工作,還是應該使用更多內存,然後可能有更好的分離和可能的並行性? (雖然我不認爲解碼會成爲瓶頸,但這將是網絡)。

還是有一種模式,我可以使用TPL數據流,解決我的問題更好?

+1

選擇相當直接。只有你可以判斷每種方法的優點。如果你想清楚解碼階段(也許你可以更好地管理資源/併發性),那麼解碼到MemoryStream似乎是一個好主意,但在內存方面會更昂貴。另一方面,如果您的數據包解析TransformBlock不受CPU額外解碼負載的限制,只需讓這些數據流執行其魔術...... – spender

+0

這會成爲問題的唯一時間是當您處於負載繁重和隊列/端口(或任何他們在TPLDF中調用的名稱)時開始備份。當您遇到這種情況時,仔細測量可能會給您更好的答案。 – spender

+0

爲什麼你甚至想把它放到一個單獨的塊?爲什麼不把它添加到其中一個現有的塊? – svick

回答

1

一如既往,這是一種折衷,只能由您做出決定。

我會用最簡單的方法來連接這兩個塊,並讓寫入塊「吸收」增加的壓縮複雜性,因爲TDF塊可以在需要時增加其並行性。 但是,我只會這樣做,如果該塊沒有有限的並行性(MaxDegreeOfParallelism)。

如果存在限制,那麼我會按照您所描述的那樣處理壓縮塊中的實際壓縮。這種行爲可以以非常高的並行性完成,並且這些內存緩衝區似乎並不是一個如此大的問題。

如果是這樣,您可以添加一個緩衝池,因此您的緩衝區計數將被限制爲該塊的MaxDegreeOfParallelism,並且您只需要在應用程序的生命週期中分配一次這些緩衝區。