簡體   English   中英

TcpClient性能 - 發送4個標量值比發送包含所有值的1字節數組慢得多

[英]TcpClient performance - sending 4 scalar values much slower than sending 1 byte array containing all values

我正在編寫一個應用程序,其中兩個應用程序(比如服務器和客戶端)通過localhost上的基於TCP的連接進行通信。

代碼對性能至關重要,所以我盡量優化。

以下代碼來自服務器應用程序。 要發送消息,我的天真方法是從TcpClient的流創建BinaryWriter,並通過BinaryWriter寫入消息的每個值。 所以我們假設消息由4個值組成; 一個長的,然后是一個bolean值,然后再多2個; 天真的做法是:

TcpClient client = ...;
var writer = new BinaryWriter(client.GetStream());

// The following takes ca. 0.55ms:

writer.Write((long)123);
writer.Write(true);
writer.Write((long)456);
writer.Write((long)2);

使用0.55ms的執行時間,這讓我感覺相當慢。 然后,我嘗試了以下代碼:

TcpClient client = ...;

 // The following takes ca. 0.15ms:

var b1 = BitConverter.GetBytes((long)123);
var b2 = BitConverter.GetBytes(true);
var b3 = BitConverter.GetBytes((long)456);
var b4 = BitConverter.GetBytes((long)2);

var result = new byte[b1.Length + b2.Length + b3.Length + b4.Length];
Array.Copy(b1, 0, result, 0, b1.Length);
Array.Copy(b2, 0, result, b1.Length, b2.Length);
Array.Copy(b3, 0, result, b1.Length + b2.Length, b3.Length);
Array.Copy(b4, 0, result, b1.Length + b2.Length + b3.Length, b4.Length);

client.GetStream().Write(result, 0, result.Length);

后者在大約0.15ms內運行,而第一種方法大約需要0.55ms,因此慢3-4倍。

我在想......為什么? 更重要的是,盡可能快地編寫消息的最佳方式是什么(同時保持至少最低的代碼可讀性)?

我現在想到的唯一方法是創建一個類似於BinaryWriter的自定義類; 但是不是直接將每個值寫入流,而是緩沖一定數量的數據(比如10,000個字節等),並且只在內部緩沖區已滿時將其發送到流,或者明確表示某些.Flush()方法。被叫(例如,當寫完消息時)。

這應該有用,但是我想知道我是否過於復雜化,並且有一種更簡單的方法來實現良好的性能? 如果這確實是最好的方法 - 任何建議理想情況下內部緩沖區應該有多大? 將它與Winsock的發送和接收緩沖區對齊是否有意義,或者最好使它盡可能大(或者說在合理的內存限制下如此大)?

謝謝!

第一個代碼執行四個阻止網絡IO操作,而第二個代碼只執行一個。 通常,大多數類型的IO操作都會產生相當大的開銷,因此您可能希望避免小的寫入/讀取和批處理。

您應始終序列化您的數據,如果可行,則將其批量處理為單個消息。 這樣您就可以避免盡可能多的IO開銷。

可能問題更多的是關於進程間通信(IPC)而不是TCP協議。 IPC有多種選擇(請參閱Microsoft Dev Center上的“ 進程間通信”頁面)。 首先,您需要定義系統要求(系統應如何執行/擴展),而不是選擇使用性能指標在您的特定方案中最佳選擇的最簡單選項。

Joe Duffy撰寫的Performance Culture文章的相關摘錄:

體面的工程師直覺。 好的工程師測量。 偉大的工程師做到了。

雖然衡量什么?

我將指標分為兩個不同的類別:

  • 消費指標。 這些直接測量運行測試所消耗的資源。
  • 觀察指標。 它們使用系統“外部”的度量來衡量運行測試的結果。

消耗度量的示例是硬件性能計數器,諸如退出的指令,數據高速緩存未命中,指令高速緩存未命中,TLB未命中和/或上下文切換。 軟件性能計數器也是很好的候選者,例如I / O數量,分配(和收集)的內存,中斷和/或系統調用的數量。 觀察指標的示例包括由雲提供商計費的運行時間和運行測試的成本。 由於各種原因,兩者顯然都很重要。

對於TCP,當你可以一次寫入數據時,我沒有看到將數據寫成小塊的重點。 您可以使用BufferedStream來裝飾TCP客戶端流實例並使用相同的BinaryWriter 只是確保不要以強制BufferedStream嘗試將內部緩沖區寫回流的方式混合讀取和寫入,因為NetworkStream不支持該操作。 請參閱使用TCP時發送1個大塊或許多小塊是否更好? 為什么BufferedStream.Write會拋出“此流不支持搜索操作”? 關於StackOverflow的討論。

有關更多信息,請查看命名管道示例C#套接字與管道C#中的IPC機制 - 用法和最佳實踐何時使用.NET BufferedStream類? 什么時候優化過早? 關於StackOverflow的討論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM