2013-10-03 38 views
11

我見過幾篇比較select()poll()epoll()的文章,我見過很多指南討論了帶有多個套接字的select()的實際用法。socket select()vs non-block recv

但是,我似乎無法找到的是與沒有select()的非阻塞recv()調用的比較。如果只有1個套接字讀取和1個套接字寫入,是否有任何理由使用select()調用?當沒有可用的數據時,recv()方法可以設置爲不阻止並返回錯誤(WSAEWOULDBLOCK),那麼當您沒有其他套接字進行檢查時,爲什麼還要打電話給select()?非阻塞recv()調用速度更慢嗎?

+0

這可能是您實施的所有細節。你試過了嗎? –

+0

當沒有數據需要連續閱讀時,你會怎麼做?永遠循環?或者使用select或poll或epoll?無論阻塞還是非阻塞,您都需要以某種方式等待數據。 – goji

+0

是的,正如@Troy所說的,這樣你就可以實現主動等待 - 這意味着沒有什麼可讀的時候,處理器沒有任何憐憫。 – zoska

回答

9

如果您在調查無限耗盡cpu時間的情況下等待套接字上的數據,那麼您不希望使用其他方法進行無阻塞的recv調用。

如果您沒有其他套接字可以在同一個線程中進行檢查並且沒有別的事情可做,那麼阻塞的讀取調用可能是最有效的解決方案。雖然在這種情況下,考慮到這種效率就像是過早的優化。

隨着套接字數量的增加,這些類型的考慮只會發揮作用。

非阻塞調用在處理單個線程上的多個套接字的上下文中速度更快。

+1

我從你的迴應和下面的迴應中看出,循環recv()是CPU密集型的,這讓我懷疑循環中的select()實際上會掛起線程嗎?這可能正是我想知道的差異。 此外,如果這是真的,我會懷疑它只會暫停持續時間,這將選擇變成阻塞呼叫? 學習這個,你會如何建議一個2套接字線程(1代表輸入,1代表輸出),你需要它們以最大速度進行處理,但是當隊列中有新數據可用時,輸出只會很重要? –

+0

在調用'select()'之前,你填充它的結構(bitsets)。如果已準備好寫入數據,則將輸出套接字設置爲寫入位集,輸入套接字將始終設置爲讀取位集。這是非常典型的選擇用法,谷歌上有很多例子。 – goji

+1

這本書是套接字聖經imo:http://www.amazon.com/UNIX-Network-Programming-Networking-Sockets/dp/013490012X – goji

3

如果沒有數據可用,並且您使用非阻塞IO,recv()將立即返回。 那麼該程序應該做什麼?您需要循環調用recv(),直到數據可用 - 這只是使用CPU而已,幾乎沒有任何理由。

recv()上旋轉並且以這種方式刻錄CPU是非常不理想的;你寧願讓這個過程等待,直到數據可用並被喚醒;這就是select()/poll()和類似的東西。

而且,sleep()在循環中爲了不燒CPU也不是好的解決方法。您會在處理中引入高延遲,因爲只要數據可用,程序將無法處理數據。

5

select()和朋友可以讓你設計工作流程,使得一個套接字的慢度不會妨礙你爲另一個套接字服務的速度。假設數據從接收套接字快速到達,並且您希望儘可能快地接受數據並將其存儲在內存緩衝區中。但發送套接字很慢。當你填滿了OS的發送緩衝區並且給你EWOULDBLOCK時,你可以發出select()來等待接收和發送套接字。如果接收套接字上的新數據到達,或者釋放了一些緩衝區,並且您可以向發送套接字寫入更多數據(以先發生者爲準),則會發生select()

當然,對於select()更實際的用例是,當您有多個套接字來讀取和/或要寫入數據時,或者您必須在兩個方向上的兩個套接字之間傳遞數據時。

實際上,select()會告訴您何時對套接字的下一次讀取或寫入操作已知成功,因此如果您只在select允許時嘗試讀取和寫入,即使您沒有選擇,您的程序也幾乎可以工作使插座非阻塞!這樣做仍然是不明智的,因爲存在邊緣情況下,儘管select()報告套接字爲「就緒」,但下一個操作仍可能阻塞。

另一方面,由於reason explained by @Troy,使套接字非阻塞和不使用select()幾乎不可取。