其實在.net socket編寫高性能穩定方面的資料真的比較少,一個實質性的測試數據結果對比就更少了.我們可以從http://msdn.microsoft.com/zh-cn/magazine/cc163356.aspx看到MS說net 2.0 sp1后的socket通訊能力非常強勁,可以同時掛起6W個IO(可以簡單地認為可以在一秒內send+receive可以達到6W或更高),但要找這個數據的測試似乎很難.但在一篇MS關於WCF的性能測試中基於tcp部署的性能在一台4路服務器中可以達到這個量(http://msdn.microsoft.com/en-us/library/bb310550.aspx).那WCF可以達到那基於c# socket實現達到這樣的IO處理能力應該完成沒問題.經常一段時間的努力即使在一台core e4300 5年前的PC上完全勝任每秒6W IO的處理能力,還包括數據接收,協議分析對像序列化寫入.
以下是一些經驗總結:
Buffer Pool
這個相信不用說,MSDN上也介紹這種用法.但如何分配這個buffer大小呢?我們一般會一條消息用一個buffer,這個時候我們就很難分配了,不得不按最大消息長度來定義buffer長度,這樣做從內存分配上來說是極其不合理的.不過現在內存多不用計較(也許).但還存在一種問題就是send的時候一般針對buffer的,當消息小的時候就不得不按消息的數量來操作IO,如果buffer的靈活性更好如小的消息可以多個寫入一個buffer,大的消息可以寫入幾個buffer.這樣即能達到內存使用合理.也能控制最少的IO處理最多的信息達到更好的性能.
SocketAsyncEventArgs池需要嗎?
這個MSDN上也有介紹這種用法,但就存在一個如何分配的問題,連接產生的時候分配,連接斷開的時候回收?如果是這個SAEA怎樣分配buffer大小(別輕易地使用SetBuffer(byte[],int,int)方法);不得不面對以上Buffer說的問題.所以SEAE和Buffer Pool一樣大小來分配池結合使用,用的時候拿用完回收到池. 其實SEAE最好是和BUFFER整合在一起,這樣做的好處就是在高並發的時候可以節省大量的byte[] Copy.
隊列的使用
隊列的使用就是更好控制線程處理數據,既然一個線程就能更好地完成工作,可必要用更多的線程去做呢.記住用最少的線程完成最多的事情.
在運行期內你能做到最少化內存分配嗎?
你能讓一些getByes方法不產生new byte[]嗎?好好看下MSDN相關對像方法看有什么途徑來達到這種效果.
不於過於自信多用些分析工具
也許你有着很多年的經驗,也用一些計時器來衡量過代碼的執行行性能.但有時候你真的很難發現原來性能並不存在於你測的地方.不要只關注於代碼的CPU執行時間,別忘了.NET下還有一個巨頭GC.用性能分析工具分析代碼的執行時間同時,不要忘了分析一下代碼在某些情況下的內存分配情況.VS2010就提供了這些方便的分析工具.
以下是這段時間優化的測試情況
測試結果一:
1K連接分別獲取一個對像和一個列表對像
單一對像信息
class GetResponse : IMessage { public User User; public void Save(BufferWriter writer) } class User : IMessage { public string Name; public string EMail; public string City; public string Counrty; public void Save(BufferWriter writer) { writer.Write(Name); writer.Write(EMail); writer.Write(City); writer.Write(Counrty); } public void Load(BufferReader reader) { Name = reader.ReadString(); EMail = reader.ReadString(); City = reader.ReadString(); Counrty = reader.ReadString(); } }
列表對像信息(5條)
class Response : IMessage { private IList<Order> mOrders = new List<Order>(); public IList<Order> Orders { get { return mOrders; } } } class Order : IMessage { public int OrderID; public string CustomerID; public int EmployeeID; public long OrderDate; public long RequiredDate; public string ShipName; public string ShipAddress; public string ShipCity; public string ShipRegion; public string ShipPostalCode; public string ShipCountry; public void Save(BufferWriter writer) { writer.Write(OrderID); writer.Write(CustomerID); writer.Write(EmployeeID); writer.Write(OrderDate); writer.Write(RequiredDate); writer.Write(ShipName); writer.Write(ShipAddress); writer.Write(ShipCity); writer.Write(ShipRegion); writer.Write(ShipPostalCode); writer.Write(ShipCountry); } public void Load(BufferReader reader) { OrderID = reader.ReadInt32(); CustomerID = reader.ReadString(); EmployeeID = reader.ReadInt32(); OrderDate = reader.ReadInt64(); RequiredDate = reader.ReadInt64(); ShipName = reader.ReadString(); ShipAddress = reader.ReadString(); ShipCity = reader.ReadString(); ShipRegion = reader.ReadString(); ShipPostalCode = reader.ReadString(); ShipCountry = reader.ReadString(); } }
測試結果
測試結果2:
由於局域網帶寬限制,所以只能測試2K和3K連接下的單一對象獲取
除了以上測試結果外,還進行了同場景500物體狀態變更廣播,在core e4300也完全能勝任,每秒轉發50W的消息量.每個client的消息延時在100ms以內.
同場景物體廣播測試程序:http://www.henryfan.net/file.axd?file=2012%2f3%2fBroadcastTest.rar (想測試效果請分開電腦運行,如果你的網絡是100mb的話最大只能運行5個client,如果服務器的cpu低於core e4300也有可能支持不了500同屏)