2010-07-29 165 views
9

幾天前,我必須調查一個問題,即當我的應用程序顯然處於空閒狀態時,它顯示的CPU使用率異常高。我將問題追蹤到一個循環,該循環意圖在套接字已設置爲O_NONBLOCK時調用recvfrom調用,從而導致自旋鎖定。解決此問題的方法有兩種:將套接字設置爲阻塞或使用pollselect輪詢套接字上的可用數據。我選擇了前者,因爲它更簡單。但我想知道爲什麼有人會創建一個非阻塞套接字,然後分別進行輪詢。不是一個阻塞的套接字是不是一樣的?有人會使用非阻塞套接字和輪詢組合的用例是什麼?在一般情況下它有什麼優點嗎?帶輪詢的非阻塞套接字

回答

7

使用poll()select()與非阻塞文件描述符爲您提供了兩個優點:

  • 您可以設置超時阻塞;
  • 您可以等待文件描述符集集合中的任何一個變爲可用。

如果您只有一個文件描述符(套接字)需要等待,並且您不介意在其上無限期等待,那麼是的;你可以使用阻塞呼叫。

第二個優勢實際上是select()和朋友的殺手級用例。這意味着您可以處理多個套接字連接,以及標準輸入和標準輸出以及可能的文件I/O,所有這些都通過單個控制線程來完成。

1

導致自旋鎖定。

這種情況通常稱爲緊密環

解決此問題的方法有兩種:將套接字設置爲阻塞或使用poll或select在套接字上輪詢可用數據。我選擇了前者,因爲它更簡單。

確定,其他的部分代碼沒有使用過poll()(或select()),並期望socket爲非阻塞模式?

否則,是的,切換到阻塞模式是最簡單的解決方案。

最佳向後兼容的解決方案將一直呼籲recvfrom()使用poll()等待插座成爲可讀的之前。這樣可以確保代碼的其他部分能夠像以前一樣精確地工作。

但我想知道爲什麼有人會創建一個非阻塞套接字,然後單獨輪詢它。不是一個阻塞的套接字是不是一樣的?

對於recvfrom()的情況,我沒有什麼大的區別。

有人會使用非阻塞套接字和輪詢組合的用例是什麼?在一般情況下它有什麼優點嗎?

可能是一個簡單的編碼錯誤。或者有人可能會認爲在緊縮環節中調整會以某種方式提高性能。

0

將套接字編號爲nonblocking總是比較好,因爲即使阻塞的套接字有時(即當數據到達但有校驗和錯誤並且被丟棄時)也處於就緒狀態 - 即使沒有要讀取的數據。因此,使它nonblocking,通過查詢等待數據可用性然後讀取。我認爲這是主要優勢。

1

我在這裏發帖,因爲雖然問題是舊的。它出現在我的谷歌搜索不知何故,並沒有得到妥善回答。

接受的答案僅僅強調了使用非阻塞套接字的兩個優點,但沒有真正詳細說明或回答實際問題。

  • 注:在非阻塞套接字不幸的是大多數在線「教程」或代碼片段只攔截功能套接字代碼,所以知識傳播較少。

至於什麼時候你會使用一個與另一個相比......一般情況下,阻塞套接字只用於在線代碼片段。在所有(良好)生產應用中都使用非阻塞式插座。我不是無知的,如果你知道一個使用阻塞套接字的實現(並且確定這個套接字可以很好地與線程結合) - 或者讓我們更具體的在單線程中使用阻塞套接字 - 請讓我們我知道。

現在我可以給你一個很容易理解的例子,還有很多其他的例子。我們來看一個遊戲服務器的例子。無論玩家是否提供輸入(鼠標/鍵盤)來改變遊戲狀態,遊戲都會在蜱中前進,遊戲狀態會持續一段時間。現在,當多人遊戲中的套接字發揮作用時 - 如果您要使用阻塞套接字,除非玩家發送更新,否則遊戲狀態不會提前 - 因此,如果他們遇到互聯網問題,遊戲狀態將永遠不會持續更新並向所有玩家傳播更改。你會有一個相當不穩定的經歷。

現在使用非阻塞套接字,您可以在單線程上運行遊戲服務器,更新遊戲狀態以及套接字,使用...讓我們說50ms超時間隔 - 套接字數據只讀來自連接的用戶,當他們真正發送一些東西時,然後送入服務器模擬,處理並饋送到下一個打勾的遊戲狀態計算中。

+0

不要'select'和'poll'通過通知您某個特定操作**在您執行該操作時不會阻止**來緩解阻塞問題?這些優秀的生產應用程序是否仍禁用阻止? – TheBuzzSaw 2017-09-07 18:53:45

+0

@ TheBuzzSaw我不確定我是否理解這個問題。我們在這裏排除了單個套接字的用法,所以你有一套你每次使用的文件描述符,它不是select,而是實際的recv調用塊,等待數據被接收。 – 2017-09-07 20:08:10

+0

我在說,當一個程序使用'select'來複用十幾個套接字時,通常沒有必要將這些套接字放入非阻塞模式,因爲調用'select'可以確定哪些動作不會被阻塞。如果'select'返回並告訴我'45'套接字不會阻塞讀取,我可以調用'recv'而不用擔心阻塞,對吧? – TheBuzzSaw 2017-09-07 22:10:24