我在寫一個Windows 7可視化C++服務器應用程序,它應該接收3.6 MB/s的UDP數據報。 我有一個主線程recvfrom()接收數據。該套接字是一個非阻塞套接字,並具有64kB接收緩衝區。如果套接字上沒有收到數據,則線程執行睡眠(1)。UDP recvfrom線程使用太多的CPU資源
我的問題是線程幾乎佔用了我的雙核處理器的50%,我不知道如何減少它。 Wireshark只使用它的20%,所以我的主要目標是達到類似的百分比。
你有什麼想法嗎?
我在寫一個Windows 7可視化C++服務器應用程序,它應該接收3.6 MB/s的UDP數據報。 我有一個主線程recvfrom()接收數據。該套接字是一個非阻塞套接字,並具有64kB接收緩衝區。如果套接字上沒有收到數據,則線程執行睡眠(1)。UDP recvfrom線程使用太多的CPU資源
我的問題是線程幾乎佔用了我的雙核處理器的50%,我不知道如何減少它。 Wireshark只使用它的20%,所以我的主要目標是達到類似的百分比。
你有什麼想法嗎?
而不是投票,你可以使用select樣的方法來等待任何數據到您的插座或到達客戶端來決定關機:
首先讓你的插座非阻塞:
u_long nonBlocking = 0;
WSAEventSelect(sock, NULL, 0);
ioctlsocket(sock, FIONBIO, &nonBlocking);
然後用WSAWaitForMultipleEvents等待,直到數據到達,或者您想取消的recv:
int32_t MyRecv(THandle sock, WSAEVENT* recvCancelEvt,
uint8_t* buffer, uint32_t bufferBytes)
{
int32_t bytesReceived;
WSAEVENT evt;
DWORD ret;
HANDLE handles[2];
event = WSACreateEvent();
if (NULL == evt) {
return;
}
if (0 != WSAEventSelect(handle->iSocket, evt, FD_READ|FD_CLOSE)) {
WSACloseEvent(event);
return;
}
bytesReceived = recv(sock, (char*)buffer, bufferBytes, 0);
if (SOCKET_ERROR==received && WSAEWOULDBLOCK==WSAGetLastError()) {
handles[0] = evt;
handles[1] = *recvCancelEvt;
ret = WSAWaitForMultipleEvents(2, handles, FALSE, INFINITE, FALSE);
if (WAIT_OBJECT_0 == ret) {
bytesReceived = recv(handle->iSocket, (char*)buffer, bufferBytes, 0);
}
}
WSACloseEvent(evt);
return bytesReceived;
}
客戶端代碼將調用WSASetEvent
recvCancelEvt
如果它想取消recv。
謝謝你的回答。你的例子非常有啓發性。無論如何,我必須認識到,不是我簡單的接收機制效率低下,而是我處理數據的方式。 –
它看起來像你調用recvfrom的大部分時間沒有返回數據。睡1毫秒並不多。你應該考慮增加睡眠時間(便宜,但不是最佳解決方案),或者更好的解決方案,考慮使用事件驅動方法。使用select()或Windows API來阻塞,直到套接字發出信號或您感興趣的其他事件發生,然後調用recvfrom。你可能需要重新設計你的程序的主循環。
雖然基於選擇或阻塞插座解決方案是正確的做法,你正在運行的100%的一個核心是由於睡眠的行爲的原因: -
看的文檔進行WinAPI sleep():
此函數會導致線程放棄其時間片 切片,並在基於 dwMilliseconds值的時間間隔內變爲不可運行。系統時鐘以固定速率「滴答」。 如果 dwMilliseconds小於系統時鐘的分辨率,則線程可能會睡眠時間小於指定的時間長度。
所以,如果你投票,你要麼需要使用一個更大的睡眠時間(也許20毫秒,這是通常比Windows的節拍率更高一點),或使用更精確的多媒體計時器。
我會推薦使用boost :: asio :: io_service。我們收到大約200MB/s的UDP組播流量,同時最大限度地利用現代CPU。這包括完整的可靠性協議和數據分發給應用程序。分析中的瓶頸是處理,而不是boost :: asio接收。 Code here
我還沒有厭倦提升庫,但主要問題是處理而不是接收。 –
如果你感覺很勇敢,你可以考慮使用Boost :: async--但它基本上是@simonc關於使用select包裝在類庫中的答案。 – Caribou