我開發了一種與遠程SIP端點交換RTP數據包的VoIP媒體服務器。它需要很好地擴展 - 儘管我最初擔心我的C#實現不會接近它所替代的C++版本,但我使用了各種分析器來磨練實現,並且性能非常接近。使用異步UDP操作的.NET IOCP ThreadPool開銷
我通過創建可重用對象池來取消大多數對象分配,我使用ReceiveFromAsync和SendToAsync來發送/接收數據報,並且我正在使用生產者/消費者隊列在系統周圍傳遞RTP數據包。在配備2個2.4GHz Xeon處理器的機器上,我現在可以處理大約1000個併發流,每個流每秒發送/接收50個數據包。但是,迭代配置文件/調整/配置文件讓我着迷 - 我相信在那裏有更多的效率!
觸發處理的事件是在SocketAsyncEventArgs上調用的Completed委託 - 它通過處理管道發送RTP數據包。
其餘的挫折是在IOCP線程池中似乎存在很大的開銷。分析器顯示只有72%的包含採樣時間在'我的代碼'中 - 之前的時間似乎是線程池開銷(下面的堆棧幀)。
所以,我的問題是:
- 我失去了我的理解是什麼?
- 可以減少這種開銷嗎?
- 是否有可能取代異步套接字函數使用的線程池來使用自定義輕量級線程池,並且開銷較小?每秒在Windows
100% MediaGateway 95.35% Thread::intermediateThreadProc(void *) 88.37% ThreadNative::SetDomainLocalStore(class Object *) 88.37% BindIoCompletionCallbackStub(unsigned long,unsigned long,struct _OVERLAPPED *) 86.05% BindIoCompletionCallbackStubEx(unsigned long,unsigned long,struct _OVERLAPPED *,int) 86.05% ManagedThreadBase::ThreadPool(struct ADID,void (*)(void *),void *) 86.05% CrstBase::Enter(void) 86.05% AppDomainStack::PushDomain(struct ADID) 86.05% Thread::ShouldChangeAbortToUnload(class Frame *,class Frame *) 86.05% AppDomainStack::ClearDomainStack(void) 83.72% ThreadPoolNative::CorWaitHandleCleanupNative(void *) 83.72% [email protected]@@84 83.72% DispatchCallDebuggerWrapper(unsigned long *,unsigned long,unsigned long *,unsigned __int64,void *,unsigned __int64,unsigned int,unsigned char *,class ContextTransitionFrame *) 83.72% DispatchCallBody(unsigned long *,unsigned long,unsigned long *,unsigned __int64,void *,unsigned __int64,unsigned int,unsigned char *) 83.72% MethodDesc::EnsureActive(void) 81.40% [email protected] 81.40% System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint32,uint32,valuetype System.Threading.NativeOverlapped*) 76.74% System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(uint32,uint32,valuetype System.Threading.NativeOverlapped*) 76.74% System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(valuetype System.Net.Sockets.SocketError,int32,valuetype System.Net.Sockets.SocketFlags) 74.42% System.Threading.ExecutionContext.Run(class System.Threading.ExecutionContext,class System.Threading.ContextCallback,object) 72.09% System.Net.Sockets.SocketAsyncEventArgs.ExecutionCallback(object) 72.09% System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(class System.Net.Sockets.SocketAsyncEventArgs)
我不知道任何配置選項或類似的,允許以任何方式調整IOCP線程池。我想你所能做的就是優化代碼中的72%。 – dtb 2011-05-25 22:28:34
@dtb不幸的是,大約40%的時間隨後花在Socket中。SendToAsync - 所以我只剩下32%的比賽了 - 我覺得我已經儘可能多的去了那一場比賽。也許我已經接近.NET的限制,只需要擴展硬件。 – MikeBrom 2011-05-26 07:44:13
這可能只是分析的人工產物。你確定你推送的數據超過服務器可以處理的數量嗎?有很多樂觀鎖定和自旋鎖定,當負載足夠大時有助於性能,但在分析時會產生奇怪的數據。很可能是因爲沒有完成任何工作,只是等待下一個數據。也可能是它偶然碰巧是GC凍結過程的地方。異步代碼對配置文件來說非常棘手 - 我有很多「問題」,這些問題都是分析本身的工件。 – Luaan 2015-02-24 13:41:09