基礎(chǔ):操作系統(tǒng)IO多路復(fù)用機(jī)制。
IO多路復(fù)用機(jī)制,常見(jiàn)的實(shí)現(xiàn)方法有select,poll,epoll,kqueue.
IO多路復(fù)用是服務(wù)器程序開(kāi)發(fā)的核心,也是研究服務(wù)器程序源代碼的基礎(chǔ)。
這里做個(gè)簡(jiǎn)單的介紹。
這里試圖用非程序的方式來(lái)說(shuō)明這個(gè)機(jī)制。
舉個(gè)例子:
辦公室有3個(gè)可加熱飲料機(jī),分別提供橙汁,茶水,豆?jié){。
飲料機(jī)有一個(gè)指示燈,紅色表示正在加熱,綠色表示完成加熱。
有3個(gè)水壺用于裝熱飲,這里假設(shè),水壺容量很大,飲料機(jī)要多次加熱才能裝滿一壺。
會(huì)議室要開(kāi)會(huì),任務(wù):接滿3水壺加熱完成的飲料到會(huì)議室備用。
問(wèn)題:怎么接滿三水壺?zé)犸嫞?/h3>
(這個(gè)問(wèn)題也太簡(jiǎn)單了吧,有必要討論嗎?)
辦法一:
先拿個(gè)一水壺接橙汁,指示燈為紅色時(shí)等待,綠色時(shí)接,飲料機(jī)多次加熱,多次等待,等接滿一壺后,在同樣的一次接滿茶水,豆?jié){。
這個(gè)辦法很簡(jiǎn)單,只需依次等待。
當(dāng)我們會(huì)發(fā)現(xiàn),在等待橙汁加熱的時(shí)候,茶水和豆?jié){可能已經(jīng)加熱就緒了。
于是我們改進(jìn)了這個(gè)辦法。
辦法二:
同時(shí)監(jiān)控3個(gè)飲料機(jī)的指示燈,哪個(gè)燈變綠,就去接哪個(gè)。
這樣效率提高了很多。
細(xì)節(jié)上看,辦法一很簡(jiǎn)單,只需依次操作。
辦法二,減少了等待時(shí)間,多了一個(gè)監(jiān)控工作。
這里還有個(gè)飲料機(jī)列表的概念,和飲料機(jī)添加,移除操作。
即需要哪些飲料機(jī),和需求變動(dòng)的操作。
以上例子,我們需求是橙汁,茶水和豆?jié){,如果需求變動(dòng),需要加入牛奶或者不需要豆?jié){。
辦法一和辦法二的飲料機(jī)列表要做調(diào)整,這一點(diǎn)兩者是類(lèi)似的。
但是辦法二也有不足的地方:需要時(shí)時(shí)查看指示燈的狀態(tài)。
只有3個(gè)飲料機(jī)的情況,不易察覺(jué)這個(gè)過(guò)程,試想如果有1000個(gè)飲料機(jī),我們要挨個(gè)查看這1000個(gè)指示燈。
于是我們改進(jìn)了這個(gè)方法。
辦法三:
每個(gè)飲料機(jī)加個(gè)聲音提示功能,即加熱完成后聲音提醒一下。
這樣的好處是在多個(gè)飲料機(jī)的情況下,我們不用時(shí)時(shí)檢查每個(gè)指示燈的狀態(tài)。
從主動(dòng)檢查變成被動(dòng)提醒的改進(jìn),大大提高了效率。這就是傳說(shuō)中的基于事件的IO多路復(fù)用機(jī)制
現(xiàn)在我們感覺(jué)良好了,當(dāng)還有改進(jìn)的地方,
試想下,如果天氣寒冷,電力不足,飲料加熱很慢。
即使我們同時(shí)監(jiān)控3個(gè)飲料機(jī),也會(huì)等待很久,即長(zhǎng)時(shí)間沒(méi)有任何一個(gè)加熱就緒的信號(hào)。
同時(shí)我們還有其他任務(wù),諸如打印報(bào)表,準(zhǔn)備投影儀等。
聰明的人變想到,不能這樣一直等下去,等一會(huì)兒,飲料機(jī)沒(méi)動(dòng)靜,就去做其他事,其他事做好了,再過(guò)來(lái)接飲料。
這里引入了一個(gè)超時(shí)的概念,即一次等待最長(zhǎng)的時(shí)間。(當(dāng)然,可以設(shè)定不超時(shí))
加入了超時(shí)支持,辦法三的效率就更高了,這也是現(xiàn)在多數(shù)服務(wù)器程序的機(jī)制。
整個(gè)舉例中有個(gè)隱含的要求就是,一個(gè)水壺不能同時(shí)裝兩種飲料。
即一個(gè)水壺一次只能裝同一種飲料,橙汁和茶水不能混在一起。
這話似乎有些多余,橙汁和茶水混在一起是很顯然的錯(cuò)誤。
對(duì)于程序開(kāi)發(fā),這個(gè)錯(cuò)誤卻很容易發(fā)生 .
所以這里做個(gè)提醒: 橙汁和茶水必要混在一起,味道不好。
以上為日常例子,現(xiàn)在回到技術(shù):
一個(gè)飲水機(jī)的水龍頭相當(dāng)于一個(gè)輸入的文件句柄(fd),
指示燈變綠,句柄可讀信號(hào)。
水壺表示緩沖(BUFFER)
這個(gè)例子以輸出為例,輸入的情況類(lèi)似。
辦法二對(duì)應(yīng)與select方法,也可以加入超時(shí)設(shè)置。這個(gè)方法因?yàn)樾什桓撸驯籩poll或kqueue取代,
一些開(kāi)源軟件在windows下面使用這個(gè)方法。
辦法三對(duì)應(yīng)于epoll,kqueue方法,因?yàn)楦咝В謩e在Linux和FreeBSD平臺(tái)廣泛使用。