2013-01-18 48 views
2

我在寫一個Windows 7可視化C++服務器應用程序,它應該接收3.6 MB/s的UDP數據報。 我有一個主線程recvfrom()接收數據。該套接字是一個非阻塞套接字,並具有64kB接收緩衝區。如果套接字上沒有收到數據,則線程執行睡眠(1)。UDP recvfrom線程使用太多的CPU資源

我的問題是線程幾乎佔用了我的雙核處理器的50%,我不知道如何減少它。 Wireshark只使用它的20%,所以我的主要目標是達到類似的百分比。

你有什麼想法嗎?

+0

如果你感覺很勇敢,你可以考慮使用Boost :: async--但它基本上是@simonc關於使用select包裝在類庫中的答案。 – Caribou

回答

4

而不是投票,你可以使用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; 
} 

客戶端代碼將調用WSASetEventrecvCancelEvt如果它想取消recv。

+0

謝謝你的回答。你的例子非常有啓發性。無論如何,我必須認識到,不是我簡單的接收機制效率低下,而是我處理數據的方式。 –

0

它看起來像你調用recvfrom的大部分時間沒有返回數據。睡1毫秒並不多。你應該考慮增加睡眠時間(便宜,但不是最佳解決方案),或者更好的解決方案,考慮使用事件驅動方法。使用select()或Windows API來阻塞,直到套接字發出信號或您感興趣的其他事件發生,然後調用recvfrom。你可能需要重新設計你的程序的主循環。

1

雖然基於選擇或阻塞插座解決方案是正確的做法,你正在運行的100%的一個核心是由於睡眠的行爲的原因: -

看的文檔進行WinAPI sleep()

此函數會導致線程放棄其時間片 切片,並在基於 dwMilliseconds值的時間間隔內變爲不可運行。系統時鐘以固定速率「滴答」。 如果 dwMilliseconds小於系統時鐘的分辨率,則線程可能會睡眠時間小於指定的時間長度。

所以,如果你投票,你要麼需要使用一個更大的睡眠時間(也許20毫秒,這是通常比Windows的節拍率更高一點),或使用更精確的多媒體計時器。

0

我會推薦使用boost :: asio :: io_service。我們收到大約200MB/s的UDP組播流量,同時最大限度地利用現代CPU。這包括完整的可靠性協議和數據分發給應用程序。分析中的瓶頸是處理,而不是boost :: asio接收。 Code here

+0

我還沒有厭倦提升庫,但主要問題是處理而不是接收。 –