IO多路复用select,poll epoll以及区别
看這個(gè)一次讀懂 Select、Poll、Epoll IO復(fù)用技術(shù) 文章來(lái)簡(jiǎn)單理解下,如果不是很明白的話,可以參考下面轉(zhuǎn)的知乎上面白話文列子
作者:Leslie
鏈接:https://www.zhihu.com/question/32163005/answer/76577586
來(lái)源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
要弄清問(wèn)題 先要知道問(wèn)題的出現(xiàn)原因
原因:
由于進(jìn)程的執(zhí)行過(guò)程是線性的(也就是順序執(zhí)行),當(dāng)我們調(diào)用低速系統(tǒng)I/O(read,write,accept等等),進(jìn)程可能阻塞,此時(shí)進(jìn)程就阻塞
在這個(gè)調(diào)用上,不能執(zhí)行其他操作.阻塞很正常. 接下來(lái)考慮這么一個(gè)問(wèn)題:一個(gè)服務(wù)器進(jìn)程和一個(gè)客戶端進(jìn)程通信,服務(wù)器端read(sockfd1,bud,bufsize),此時(shí)客戶端進(jìn)程沒(méi)有發(fā)送數(shù)據(jù),那么read(阻塞調(diào)用)將阻塞直到客戶端調(diào)用write(sockfd,but,size)
發(fā)來(lái)數(shù)據(jù). 在一個(gè)客戶和服務(wù)器通信時(shí)這沒(méi)什么問(wèn)題,當(dāng)多個(gè)客戶與服務(wù)器通信時(shí),若服務(wù)器阻塞于其中一個(gè)客戶sockfd1,當(dāng)另一個(gè)客戶的數(shù)據(jù)到達(dá)套接字sockfd2時(shí),服務(wù)器不能處理,仍然阻塞在read(sockfd1,...)上;此時(shí)問(wèn)題就出現(xiàn)了,不能及時(shí)處理另一個(gè)客戶的
服務(wù),咋么辦?I/O多路復(fù)用來(lái)解決!I/O多路復(fù)用:繼續(xù)上面的問(wèn)題,有多個(gè)客戶連接,sockfd1,sockfd2,sockfd3..sockfdn同時(shí)監(jiān)聽(tīng)這n個(gè)客戶,當(dāng)其中有一個(gè)發(fā)來(lái)消息時(shí)就從select的阻塞中返回,然后就調(diào)用read讀取收到消息的sockfd,然后又循環(huán)回select
阻塞;
這樣就不會(huì)因?yàn)樽枞谄渲幸粋€(gè)上而不能處
理另一個(gè)客戶的消息
Q:
那這樣子,在讀取socket1的數(shù)據(jù)時(shí),如果其它socket有數(shù)據(jù)來(lái),那么也要等到socket1讀取完了才能繼續(xù)讀取其它socket的數(shù)據(jù)吧。那不是也阻塞住了嗎?而且讀取到的數(shù)據(jù)也要開(kāi)啟線程處理吧,那這和多線程IO有什么區(qū)別呢?
A:
1.CPU本來(lái)就是線性的 不論什么都需要順序處理 并行只能是多核CPU
http://2.io多路復(fù)用本來(lái)就是用來(lái)解決對(duì)多個(gè)I/O監(jiān)聽(tīng)時(shí),一個(gè)I/O阻塞影響其他I/O的問(wèn)題,跟多線程沒(méi)關(guān)系.
3.跟多線程相比較,線程切換需要切換到內(nèi)核進(jìn)行線程切換,需要消耗時(shí)間和資源. 而I/O多路復(fù)用不需要切換線/進(jìn)程,效率相對(duì)較高,特別是對(duì)高并發(fā)的應(yīng)用nginx就是用I/O多路復(fù)用,故而性能極佳.但多線程編程邏輯和處理上比I/O多路復(fù)用簡(jiǎn)單.而I/O多路復(fù)用處理起來(lái)較為復(fù)雜.
作者:匿名用戶
鏈接:https://www.zhihu.com/question/32163005/answer/55687802
來(lái)源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
這些名詞比較繞口,理解涵義就好。一個(gè)epoll場(chǎng)景:一個(gè)酒吧服務(wù)員(一個(gè)線程),前面趴了一群醉漢,突然一個(gè)吼一聲“倒酒”(事件),你小跑過(guò)去給他倒一杯,然后隨他去吧,突然又一個(gè)要倒酒,你又過(guò)去倒上,就這樣一個(gè)服務(wù)員服務(wù)好多人,有時(shí)沒(méi)人喝酒,服務(wù)員處于空閑狀態(tài),可以干點(diǎn)別的玩玩手機(jī)。至于epoll與select,poll的區(qū)別在于后兩者的場(chǎng)景中醉漢不說(shuō)話,你要挨個(gè)問(wèn)要不要酒,沒(méi)時(shí)間玩手機(jī)了。io多路復(fù)用大概就是指這幾個(gè)醉漢共用一個(gè)服務(wù)員。
作者:levin
鏈接:https://www.zhihu.com/question/32163005/answer/255238636
來(lái)源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
?
IO 多路復(fù)用是5種I/O模型中的第3種,對(duì)各種模型講個(gè)故事,描述下區(qū)別:
故事情節(jié)為:老李去買(mǎi)火車(chē)票,三天后買(mǎi)到一張退票。參演人員(老李,黃牛,售票員,快遞員),往返車(chē)站耗費(fèi)1小時(shí)。
1.阻塞I/O模型
老李去火車(chē)站買(mǎi)票,排隊(duì)三天買(mǎi)到一張退票。
耗費(fèi):在車(chē)站吃喝拉撒睡 3天,其他事一件沒(méi)干。
2.非阻塞I/O模型
老李去火車(chē)站買(mǎi)票,隔12小時(shí)去火車(chē)站問(wèn)有沒(méi)有退票,三天后買(mǎi)到一張票。
耗費(fèi):往返車(chē)站6次,路上6小時(shí),其他時(shí)間做了好多事。
3.I/O復(fù)用模型
1.select/poll
老李去火車(chē)站買(mǎi)票,委托黃牛,然后每隔6小時(shí)電話黃牛詢問(wèn),黃牛三天內(nèi)買(mǎi)到票,然后老李去火車(chē)站交錢(qián)領(lǐng)票。
耗費(fèi):往返車(chē)站2次,路上2小時(shí),黃牛手續(xù)費(fèi)100元,打電話17次
2.epoll
老李去火車(chē)站買(mǎi)票,委托黃牛,黃牛買(mǎi)到后即通知老李去領(lǐng),然后老李去火車(chē)站交錢(qián)領(lǐng)票。
耗費(fèi):往返車(chē)站2次,路上2小時(shí),黃牛手續(xù)費(fèi)100元,無(wú)需打電話
4.信號(hào)驅(qū)動(dòng)I/O模型
老李去火車(chē)站買(mǎi)票,給售票員留下電話,有票后,售票員電話通知老李,然后老李去火車(chē)站交錢(qián)領(lǐng)票。
耗費(fèi):往返車(chē)站2次,路上2小時(shí),免黃牛費(fèi)100元,無(wú)需打電話
5.異步I/O模型
老李去火車(chē)站買(mǎi)票,給售票員留下電話,有票后,售票員電話通知老李并快遞送票上門(mén)。
耗費(fèi):往返車(chē)站1次,路上1小時(shí),免黃牛費(fèi)100元,無(wú)需打電話
1同2的區(qū)別是:自己輪詢
2同3的區(qū)別是:委托黃牛
3同4的區(qū)別是:電話代替黃牛
4同5的區(qū)別是:電話通知是自取還是送票上門(mén)
?
作者:羅志宇
鏈接:https://www.zhihu.com/question/32163005/answer/55772739
來(lái)源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
這個(gè)還是很好說(shuō)清楚的。
假設(shè)你是一個(gè)機(jī)場(chǎng)的空管, 你需要管理到你機(jī)場(chǎng)的所有的航線, 包括進(jìn)港,出港, 有些航班需要放到停機(jī)坪等待,有些航班需要去登機(jī)口接乘客。
你會(huì)怎么做?
最簡(jiǎn)單的做法,就是你去招一大批空管員,然后每人盯一架飛機(jī), 從進(jìn)港,接客,排位,出港,航線監(jiān)控,直至交接給下一個(gè)空港,全程監(jiān)控。
那么問(wèn)題就來(lái)了:
- 很快你就發(fā)現(xiàn)空管塔里面聚集起來(lái)一大票的空管員,交通稍微繁忙一點(diǎn),新的空管員就已經(jīng)擠不進(jìn)來(lái)了。
- 空管員之間需要協(xié)調(diào),屋子里面就1, 2個(gè)人的時(shí)候還好,幾十號(hào)人以后 ,基本上就成菜市場(chǎng)了。
- 空管員經(jīng)常需要更新一些公用的東西,比如起飛顯示屏,比如下一個(gè)小時(shí)后的出港排期,最后你會(huì)很驚奇的發(fā)現(xiàn),每個(gè)人的時(shí)間最后都花在了搶這些資源上。
?
現(xiàn)實(shí)上我們的空管同時(shí)管幾十架飛機(jī)稀松平常的事情, 他們?cè)趺醋龅哪?#xff1f;
他們用這個(gè)東西
這個(gè)東西叫flight progress strip. 每一個(gè)塊代表一個(gè)航班,不同的槽代表不同的狀態(tài),然后一個(gè)空管員可以管理一組這樣的塊(一組航班),而他的工作,就是在航班信息有新的更新的時(shí)候,把對(duì)應(yīng)的塊放到不同的槽子里面。
?
這個(gè)東西現(xiàn)在還沒(méi)有淘汰哦,只是變成電子的了而已。。
是不是覺(jué)得一下子效率高了很多,一個(gè)空管塔里可以調(diào)度的航線可以是前一種方法的幾倍到幾十倍。
如果你把每一個(gè)航線當(dāng)成一個(gè)Sock(I/O 流), 空管當(dāng)成你的服務(wù)端Sock管理代碼的話.
第一種方法就是最傳統(tǒng)的多進(jìn)程并發(fā)模型 (每進(jìn)來(lái)一個(gè)新的I/O流會(huì)分配一個(gè)新的進(jìn)程管理。)
第二種方法就是I/O多路復(fù)用 (單個(gè)線程,通過(guò)記錄跟蹤每個(gè)I/O流(sock)的狀態(tài),來(lái)同時(shí)管理多個(gè)I/O流 。)
其實(shí)“I/O多路復(fù)用”這個(gè)坑爹翻譯可能是這個(gè)概念在中文里面如此難理解的原因。所謂的I/O多路復(fù)用在英文中其實(shí)叫 I/O multiplexing. 如果你搜索multiplexing啥意思,基本上都會(huì)出這個(gè)圖:
于是大部分人都直接聯(lián)想到"一根網(wǎng)線,多個(gè)sock復(fù)用" 這個(gè)概念,包括上面的幾個(gè)回答, 其實(shí)不管你用多進(jìn)程還是I/O多路復(fù)用, 網(wǎng)線都只有一根好伐。多個(gè)Sock復(fù)用一根網(wǎng)線這個(gè)功能是在內(nèi)核+驅(qū)動(dòng)層實(shí)現(xiàn)的。
重要的事情再說(shuō)一遍: I/O multiplexing 這里面的 multiplexing 指的其實(shí)是在單個(gè)線程通過(guò)記錄跟蹤每一個(gè)Sock(I/O流)的狀態(tài)(對(duì)應(yīng)空管塔里面的Fight progress strip槽)來(lái)同時(shí)管理多個(gè)I/O流. 發(fā)明它的原因,是盡量多的提高服務(wù)器的吞吐能力。
?
是不是聽(tīng)起來(lái)好拗口,看個(gè)圖就懂了.
?
在同一個(gè)線程里面, 通過(guò)撥開(kāi)關(guān)的方式,來(lái)同時(shí)傳輸多個(gè)I/O流, (學(xué)過(guò)EE的人現(xiàn)在可以站出來(lái)義正嚴(yán)辭說(shuō)這個(gè)叫“時(shí)分復(fù)用”了)。
?
什么,你還沒(méi)有搞懂“一個(gè)請(qǐng)求到來(lái)了,nginx使用epoll接收請(qǐng)求的過(guò)程是怎樣的”, 多看看這個(gè)圖就了解了。提醒下,ngnix會(huì)有很多鏈接進(jìn)來(lái), epoll會(huì)把他們都監(jiān)視起來(lái),然后像撥開(kāi)關(guān)一樣,誰(shuí)有數(shù)據(jù)就撥向誰(shuí),然后調(diào)用相應(yīng)的代碼處理。
------------------------------------------
了解這個(gè)基本的概念以后,其他的就很好解釋了。
select, poll, epoll 都是I/O多路復(fù)用的具體的實(shí)現(xiàn),之所以有這三個(gè)鬼存在,其實(shí)是他們出現(xiàn)是有先后順序的。
I/O多路復(fù)用這個(gè)概念被提出來(lái)以后, select是第一個(gè)實(shí)現(xiàn) (1983 左右在BSD里面實(shí)現(xiàn)的)。
select 被實(shí)現(xiàn)以后,很快就暴露出了很多問(wèn)題。
- select 會(huì)修改傳入的參數(shù)數(shù)組,這個(gè)對(duì)于一個(gè)需要調(diào)用很多次的函數(shù),是非常不友好的。
- select 如果任何一個(gè)sock(I/O stream)出現(xiàn)了數(shù)據(jù),select 僅僅會(huì)返回,但是并不會(huì)告訴你是那個(gè)sock上有數(shù)據(jù),于是你只能自己一個(gè)一個(gè)的找,10幾個(gè)sock可能還好,要是幾萬(wàn)的sock每次都找一遍,這個(gè)無(wú)謂的開(kāi)銷(xiāo)就頗有海天盛筵的豪氣了。
- select 只能監(jiān)視1024個(gè)鏈接, 這個(gè)跟草榴沒(méi)啥關(guān)系哦,linux 定義在頭文件中的,參見(jiàn)FD_SETSIZE。
- select 不是線程安全的,如果你把一個(gè)sock加入到select, 然后突然另外一個(gè)線程發(fā)現(xiàn),尼瑪,這個(gè)sock不用,要收回。對(duì)不起,這個(gè)select 不支持的,如果你喪心病狂的竟然關(guān)掉這個(gè)sock, select的標(biāo)準(zhǔn)行為是。。呃。。不可預(yù)測(cè)的, 這個(gè)可是寫(xiě)在文檔中的哦.
“If a file descriptor being monitored by select() is closed in another thread, the result is unspecified”
霸不霸氣
于是14年以后(1997年)一幫人又實(shí)現(xiàn)了poll, poll 修復(fù)了select的很多問(wèn)題,比如
- poll 去掉了1024個(gè)鏈接的限制,于是要多少鏈接呢, 主人你開(kāi)心就好。
- poll 從設(shè)計(jì)上來(lái)說(shuō),不再修改傳入數(shù)組,不過(guò)這個(gè)要看你的平臺(tái)了,所以行走江湖,還是小心為妙。
其實(shí)拖14年那么久也不是效率問(wèn)題, 而是那個(gè)時(shí)代的硬件實(shí)在太弱,一臺(tái)服務(wù)器處理1千多個(gè)鏈接簡(jiǎn)直就是神一樣的存在了,select很長(zhǎng)段時(shí)間已經(jīng)滿足需求。
但是poll仍然不是線程安全的, 這就意味著,不管服務(wù)器有多強(qiáng)悍,你也只能在一個(gè)線程里面處理一組I/O流。你當(dāng)然可以那多進(jìn)程來(lái)配合了,不過(guò)然后你就有了多進(jìn)程的各種問(wèn)題。
于是5年以后, 在2002, 大神 Davide Libenzi 實(shí)現(xiàn)了epoll.
epoll 可以說(shuō)是I/O 多路復(fù)用最新的一個(gè)實(shí)現(xiàn),epoll 修復(fù)了poll 和select絕大部分問(wèn)題, 比如:
- epoll 現(xiàn)在是線程安全的。
- epoll 現(xiàn)在不僅告訴你sock組里面數(shù)據(jù),還會(huì)告訴你具體哪個(gè)sock有數(shù)據(jù),你不用自己去找了。
?
epoll 當(dāng)年的patch,現(xiàn)在還在,下面鏈接可以看得到:
/dev/epoll Home Page
貼一張霸氣的圖,看看當(dāng)年神一樣的性能(測(cè)試代碼都是死鏈了, 如果有人可以刨墳找出來(lái),可以研究下細(xì)節(jié)怎么測(cè)的).
橫軸Dead connections 就是鏈接數(shù)的意思,叫這個(gè)名字只是它的測(cè)試工具叫deadcon. 縱軸是每秒處理請(qǐng)求的數(shù)量,你可以看到,epoll每秒處理請(qǐng)求的數(shù)量基本不會(huì)隨著鏈接變多而下降的。poll 和/dev/poll 就很慘了。
?
可是epoll 有個(gè)致命的缺點(diǎn)。。只有l(wèi)inux支持。比如BSD上面對(duì)應(yīng)的實(shí)現(xiàn)是kqueue。
其實(shí)有些國(guó)內(nèi)知名廠商把epoll從安卓里面裁掉這種腦殘的事情我會(huì)主動(dòng)告訴你嘛。什么,你說(shuō)沒(méi)人用安卓做服務(wù)器,尼瑪你是看不起p2p軟件了啦。
而ngnix 的設(shè)計(jì)原則里面, 它會(huì)使用目標(biāo)平臺(tái)上面最高效的I/O多路復(fù)用模型咯,所以才會(huì)有這個(gè)設(shè)置。一般情況下,如果可能的話,盡量都用epoll/kqueue吧。
詳細(xì)的在這里:
Connection processing methods
PS: 上面所有這些比較分析,都建立在大并發(fā)下面,如果你的并發(fā)數(shù)太少,用哪個(gè),其實(shí)都沒(méi)有區(qū)別。 如果像是在歐朋數(shù)據(jù)中心里面的轉(zhuǎn)碼服務(wù)器那種動(dòng)不動(dòng)就是幾萬(wàn)幾十萬(wàn)的并發(fā),不用epoll我可以直接去撞墻了。
?
總結(jié)
以上是生活随笔為你收集整理的IO多路复用select,poll epoll以及区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一步一步实现商城微信小程序(四)
- 下一篇: iPad app 开发概述