什么是IO多路復用


先百度或者知乎,找到這篇文章 [1] IO 多路復用是什么意思?

 

文中提到:

  

 

第一種好理解,就是來一個請求,fork一個進程,第二種提到I/O多路復用使用單個線程實現的,作者肯定沒有寫錯,因為后面的文章也都是寫的線程,我的問題是為什么不是進程來管理?參考文章[2] 里面的code 給出的是通過一個進程來服務多個client 連接請求. 我理解這是通過單進程的里面的一個線程來處理的,所以這里進程線程就不作區分.
 
還有,下面引文中一個問題問的很好
Q: 
那這樣子,在讀取socket1的數據時,如果其它socket有數據來,那么也要等到socket1讀取完了才能繼續讀取其它socket的數據吧。那不是也阻塞住了嗎?而且讀取到的數據也要開啟線程處理吧,那這和多線程IO有什么區別呢?
 
因為的答案很清楚了,加一些自己的理解,I/O多路復用解決了用單進程/線程 服務多個請求的問題,但是加入多個請求的read或者write 都ready了,還是一個一個輪流處理的,這時我們自然想到用多線程來處理多個請求,但是如果CPU是單核的還是體現不了多線程的優勢,必須是多核CPU才行.

 

  

 

這里摘錄一些精彩回復  


 

作者:羅志宇
鏈接:https://www.zhihu.com/question/32163005/answer/55772739
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

select, poll, epoll 都是I/O多路復用的具體的實現,之所以有這三個鬼存在,其實是他們出現是有先后順序的。

I/O多路復用這個概念被提出來以后, select是第一個實現 (1983 左右在BSD里面實現的)。

select 被實現以后,很快就暴露出了很多問題。
  • select 會修改傳入的參數數組,這個對於一個需要調用很多次的函數,是非常不友好的。
  • select 如果任何一個sock(I/O stream)出現了數據,select 僅僅會返回,但是並不會告訴你是那個sock上有數據,於是你只能自己一個一個的找,10幾個sock可能還好,要是幾萬的sock每次都找一遍,這個無謂的開銷就頗有海天盛筵的豪氣了。
  • select 只能監視1024個鏈接, 這個跟草榴沒啥關系哦,linux 定義在頭文件中的,參見FD_SETSIZE。
  • select 不是線程安全的,如果你把一個sock加入到select, 然后突然另外一個線程發現,尼瑪,這個sock不用,要收回。對不起,這個select 不支持的,如果你喪心病狂的竟然關掉這個sock, select的標准行為是。。呃。。不可預測的, 這個可是寫在文檔中的哦.

“If a file descriptor being monitored by select() is closed in another thread, the result is unspecified”
霸不霸氣

於是14年以后(1997年)一幫人又實現了poll, poll 修復了select的很多問題,比如
  • poll 去掉了1024個鏈接的限制,於是要多少鏈接呢, 主人你開心就好。
  • poll 從設計上來說,不再修改傳入數組,不過這個要看你的平台了,所以行走江湖,還是小心為妙。

其實拖14年那么久也不是效率問題, 而是那個時代的硬件實在太弱,一台服務器處理1千多個鏈接簡直就是神一樣的存在了,select很長段時間已經滿足需求。

但是poll仍然不是線程安全的, 這就意味着,不管服務器有多強悍,你也只能在一個線程里面處理一組I/O流。你當然可以那多進程來配合了,不過然后你就有了多進程的各種問題。

於是5年以后, 在2002, 大神 Davide Libenzi 實現了epoll.

epoll 可以說是I/O 多路復用最新的一個實現,epoll 修復了poll 和select絕大部分問題, 比如:
  • epoll 現在是線程安全的。
  • epoll 現在不僅告訴你sock組里面數據,還會告訴你具體哪個sock有數據,你不用自己去找了。 

 

 


 

作者:Leslie
鏈接:https://www.zhihu.com/question/32163005/answer/76577586
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

要弄清問題 先要知道問題的出現原因
原因:
由於進程的執行過程是線性的(也就是順序執
行),當我們調用低速系統I/O(read,write,
accept等等),進程可能阻塞,此時進程就阻塞
在這個調用上,不能執行其他操作.阻塞很正
常. 接下來考慮這么一個問題:
一個服務器進程和一個客戶端進程通信,服
務器端read(sockfd1,bud,bufsize),此時客戶
端進程沒有發送數據,那么read(阻塞調用)將
阻塞直到客戶端調用write(sockfd,but,size)
發來數據. 在一個客戶和服務器通信時這沒
什么問題,當多個客戶與服務器通信時,若服
務器阻塞於其中一個客戶sockfd1,當另一個
客戶的數據到達套接字sockfd2時,服務器不
能處理,仍然阻塞在read(sockfd1,...)上;此時
問題就出現了,不能及時處理另一個客戶的
服務,咋么辦?I/O多路復用來解決!
I/O多路復用:
繼續上面的問題,有多個客戶連接,
sockfd1,sockfd2,sockfd3..sockfdn
同時監聽這n個客戶,當其中有一個發來消息
時就從select的阻塞中返回,然后就調用read
讀取收到消息的sockfd,然后又循環回select
阻塞;
這樣就不會因為阻塞在其中一個上而不能處
理另一個客戶的消息

Q:
那這樣子,在讀取socket1的數據時,如果其它socket有數據來,那么也要等到socket1讀取完了才能繼續讀取其它socket的數據吧。那不是也阻塞住了嗎?而且讀取到的數據也要開啟線程處理吧,那這和多線程IO有什么區別呢?

A:
1.CPU本來就是線性的 不論什么都需要順序處理 並行只能是多核CPU
多路復用本來就是用來解決對多個I/O監聽時,一個I/O阻塞影響其他I/O的問題,跟多線程沒關系.
3.跟多線程相比較,線程切換需要切換到內核進行線程切換,需要消耗時間和資源. 而I/O多路復用不需要切換線/進程,效率相對較高,特別是對高並發的應用nginx就是用I/O多路復用,故而性能極佳.但多線程編程邏輯和處理上比I/O多路復用簡單.而I/O多路復用處理起來較為復雜.
 

 作者:匿名用戶
鏈接:https://www.zhihu.com/question/32163005/answer/55687802
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 
 
這些名詞比較繞口,理解涵義就好。一個epoll場景:一個酒吧服務員(一個線程),前面趴了一群醉漢,突然一個吼一聲“倒酒”(事件),你小跑過去給他倒一杯,然后隨他去吧,突然又一個要倒酒,你又過去倒上,就這樣一個服務員服務好多人,有時沒人喝酒,服務員處於空閑狀態,可以干點別的玩玩手機。至於epoll與select,poll的區別在於后兩者的場景中醉漢不說話,你要挨個問要不要酒,沒時間玩手機了。io多路復用大概就是指這幾個醉漢共用一個服務員。
 



 
select(),poll(),epoll() 都是I/O多路復用的機制。I/O 多路復用通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒,就是這個文件描述符進行讀寫操作之前),能夠通知程序進行相應的讀寫操作。但select(),poll(),epoll() 本質上都是同步 I/O,因為他們都需要在讀寫事件就緒后自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而異步 I/O 則無需自己負責進行讀寫,異步 I/O 的實現會負責把數據從內核拷貝到用戶空間。
 
 
看了上面的介紹,原理是懂了,但是具體細節不太懂,直到遇到了參考文章[2],才通透了許多
 
ref:

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com