簡單理解異步,非阻塞和 IO 復(fù)用

1.1 同步與異步

同步與異步的理解

同步與異步的重點在消息通知的方式上顺献,也就是調(diào)用結(jié)果通知的方式旗国。
同步: 當(dāng)一個同步調(diào)用發(fā)出去后,調(diào)用者要一直等待調(diào)用結(jié)果的通知后注整,才能進(jìn)行后續(xù)的執(zhí)行能曾。
異步:當(dāng)一個異步調(diào)用發(fā)出去后嫁怀,調(diào)用者不能立即得到調(diào)用結(jié)果的返回。
異步調(diào)用借浊,要想獲得結(jié)果塘淑,一般有兩種方式:

  1. 主動輪詢異步調(diào)用的結(jié)果;
  2. 被調(diào)用方通過callback來通知調(diào)用方調(diào)用結(jié)果。

生活中的例子

同步買奶茶:小明點單交錢蚂斤,然后等著拿奶茶存捺;異步買奶茶:小明點單交錢,店員給小明一個小票曙蒸,等小明奶茶做好了捌治,再來取。

異步買奶茶: 小明要想知道奶茶是否做好了纽窟,有兩種方式:

  1. 小明主動去問店員肖油,一會就去問一下:“奶茶做好了嗎?”...直到奶茶做好臂港。這叫輪訓(xùn)森枪。
  2. 等奶茶做好了,店員喊一聲:“小明审孽,奶茶好了县袱!”,然后小明去取奶茶佑力。這叫回調(diào)式散。

1.2 阻塞與非阻塞

阻塞與非阻塞的理解

阻塞與非阻塞的重點在于進(jìn)/線程等待消息時候的行為,也就是在等待消息的時候打颤,當(dāng)前進(jìn)/線程是掛起狀態(tài)暴拄,還是非掛起狀態(tài)。

阻塞調(diào)用在發(fā)出去后编饺,在消息返回之前乖篷,當(dāng)前進(jìn)/線程會被掛起,直到有消息返回反肋,當(dāng)前進(jìn)/線程才會被激活.

非阻塞調(diào)用在發(fā)出去后那伐,不會阻塞當(dāng)前進(jìn)/線程,而會立即返回石蔗。

生活中的例子

阻塞買奶茶:小明點單交錢罕邀,干等著拿奶茶,什么事都不做养距;
非阻塞買奶茶:小明點單交錢诉探,等著拿奶茶,等的過程中棍厌,時不時刷刷微博肾胯、朋友圈竖席。

1.3 總結(jié)

通過上面的分析,我們可以得知:

  1. 同步與異步敬肚,重點在于消息通知的方式;
  2. 阻塞與非阻塞毕荐,重點在于等消息時候的行為。

所以艳馒,就有了下面4種組合方式:

  1. 同步阻塞:小明在柜臺干等著拿奶茶憎亚;
  2. 同步非阻塞:小明在柜臺邊刷微博邊等著拿奶茶;
  3. 異步阻塞:小明拿著小票啥都不干弄慰,一直等著店員通知他拿奶茶第美;
  4. 異步非阻塞:小明拿著小票,刷著微博陆爽,等著店員通知他拿奶茶什往。

2. IO 復(fù)用

IO 復(fù)用例子說明

假設(shè)你是一個機(jī)場的空管,你需要管理到你機(jī)場的所有的航線慌闭, 包括進(jìn)港别威,出港,有些航班需要放到停機(jī)坪等待贡必,有些航班需要去登機(jī)口接乘客兔港。

你會怎么做?

最簡單的做法庸毫,就是你去招一大批空管員仔拟,然后每人盯一架飛機(jī), 從進(jìn)港飒赃,接客利花,排位,出港礁芦,航線監(jiān)控闭翩,直至交接給下一個空港颗管,全程監(jiān)控。

那么問題就來了:

很快你就發(fā)現(xiàn)空管塔里面聚集起來一大票的空管員挠乳,交通稍微繁忙一點,新的空管員就已經(jīng)擠不進(jìn)來了姑躲∷铮空管員之間需要協(xié)調(diào),屋子里面就1,2個人的時候還好黍析,幾十號人以后 卖怜,基本上就成菜市場了。

空管員經(jīng)常需要更新一些公用的東西阐枣,比如起飛顯示屏马靠,比如下一個小時后的出港排期奄抽,最后你會很驚奇的發(fā)現(xiàn),每個人的時間最后都花在了搶這些資源上甩鳄。

現(xiàn)實上我們的空管同時管幾十架飛機(jī)稀松平常的事情:

!(https://upload-images.jianshu.io/upload_images/7616246-d9a948e9eb0f8f31.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

他們怎么做的呢逞度?這個東西叫flight progress strip

每一個塊代表一個航班妙啃,不同的槽代表不同的狀態(tài)第晰,然后一個空管員可以管理一組這樣的塊(一組航班),而他的工作彬祖,就是在航班信息有新的更新的時候茁瘦,把對應(yīng)的塊放到不同的槽子里面。

這個東西現(xiàn)在還沒有淘汰哦储笑,只是變成電子的了而已甜熔。

是不是覺得一下子效率高了很多,一個空管塔里可以調(diào)度的航線可以是前一種方法的幾倍到幾十倍突倍。

如果你把每一個航線當(dāng)成一個Sock(I/O 流),空管當(dāng)成你的服務(wù)端Sock管理代碼的話.

第一種方法就是最傳統(tǒng)的多進(jìn)程并發(fā)模型 (每進(jìn)來一個新的I/O流會分配一個新的進(jìn)程管理腔稀。)
第二種方法就是I/O多路復(fù)用 (單個線程,通過記錄跟蹤每個I/O流(sock)的狀態(tài)羽历,來同時管理多個I/O流 焊虏。)

其實I/O多路復(fù)用這個坑爹翻譯可能是這個概念在中文里面如此難理解的原因。所謂的I/O多路復(fù)用在英文中其實叫 I/O multiplexing.

重要的事情再說一遍: I/O multiplexing 這里面的 multiplexing 指的其實是在單個線程通過記錄跟蹤每一個Sock(I/O流)的狀態(tài)(對應(yīng)空管塔里面的Fight progress strip槽)來同時管理多個I/O流. 發(fā)明它的原因秕磷,是盡量多的提高服務(wù)器的吞吐能力诵闭。

是不是聽起來好拗口,看個圖就懂了:

此處輸入圖片的描述

在同一個線程里面澎嚣, 通過撥開關(guān)的方式疏尿,來同時傳輸多個I/O流,

最初級的I/O復(fù)用

所謂的I/O復(fù)用易桃,就是多個I/O可以復(fù)用一個進(jìn)程褥琐。

采用非阻塞的模式,當(dāng)一個連接過來時晤郑,我們不阻塞住敌呈,這樣一個進(jìn)程可以同時處理多個連接了。

比如一個進(jìn)程接受了10000個連接造寝,這個進(jìn)程每次從頭到尾的問一遍這10000個連接:“有I/O事件沒磕洪?有的話就交給我處理,沒有的話我一會再來問一遍匹舞『峙福”
然后進(jìn)程就一直從頭到尾問這10000個連接,如果這1000個連接都沒有I/O事件赐稽,就會造成CPU的空轉(zhuǎn)叫榕,并且效率也很低浑侥,不好不好。

升級版的I/O復(fù)用

上面雖然實現(xiàn)了基礎(chǔ)版的I/O復(fù)用晰绎,但是效率太低了寓落。于是偉大的程序猿們?nèi)账家瓜氲娜ソ鉀Q這個問題...終于!

我們能不能引入一個代理荞下,這個代理可以同時觀察許多I/O流事件呢伶选?

當(dāng)沒有I/O事件的時候,這個進(jìn)程處于阻塞狀態(tài)尖昏;當(dāng)有I/O事件的時候仰税,這個代理就去通知進(jìn)程醒來?

于是抽诉,早期的程序猿們發(fā)明了兩個代理---select陨簇、poll

select迹淌、poll代理的原理是這樣的:

當(dāng)連接有I/O流事件產(chǎn)生的時候河绽,就會去喚醒進(jìn)程去處理。
但是進(jìn)程并不知道是哪個連接產(chǎn)生的I/O流事件唉窃,于是進(jìn)程就挨個去問:“請問是你有事要處理嗎耙饰?”......問了99999遍,哦纹份,原來是第100000個進(jìn)程有事要處理苟跪。那么,前面這99999次就白問了矮嫉,白白浪費寶貴的CPU時間片了削咆!痛哉,惜哉...

  1. select是第一個實現(xiàn) (1983 左右在BSD里面實現(xiàn))
  2. 1997年實現(xiàn)了poll.
  3. select與poll原理是一樣的蠢笋,只不過select只能觀察1024個連接,poll可以觀察無限個連接鳞陨。

上面看了昨寞,select、poll因為不知道哪個連接有I/O流事件要處理厦滤,性能也挺不好的援岩。

那么,如果發(fā)明一個代理掏导,每次能夠知道哪個連接有了I/O流事件享怀,不就可以避免無意義的空轉(zhuǎn)了嗎?

于是趟咆,超級無敵添瓷、閃閃發(fā)光的epoll梅屉,于5年以后, 在2002年被大神 Davide Libenzi 發(fā)明出來了。

epoll IO多路復(fù)用

epoll代理的原理是這樣的:

當(dāng)連接有I/O流事件產(chǎn)生的時候鳞贷,epoll就會去告訴進(jìn)程哪個連接有I/O流事件產(chǎn)生坯汤,然后進(jìn)程就去處理這個進(jìn)程。如此搀愧,多高效惰聂!

epoll 可以說是I/O 多路復(fù)用最新的一個實現(xiàn),epoll 修復(fù)了poll 和select絕大部分問題, 比如:

epoll 現(xiàn)在是線程安全的咱筛。
epoll 現(xiàn)在不僅告訴你sock組里面數(shù)據(jù)搓幌,還會告訴你具體哪個sock有數(shù)據(jù),你不用自己去找了迅箩。

可是epoll 有個致命的缺點鼻种,只有l(wèi)inux支持。于是其他的平臺實現(xiàn)類型的多路復(fù)用沙热,比如BSD上面對應(yīng)的是kqueue叉钥, win下對應(yīng)的iocp

epoll和select/poll區(qū)別

簡單說epoll和select/poll最大區(qū)別是

  1. epoll內(nèi)部使用了mmap共享了用戶和內(nèi)核的部分空間篙贸,避免了數(shù)據(jù)的來回拷貝
  2. epoll基于事件驅(qū)動投队,epoll_ctl注冊事件并注冊callback回調(diào)函數(shù),epoll_wait只返回發(fā)生的事件避免了像select和poll對事件的整個輪尋操作爵川。

3. Nginx 異步敷鸦,非阻塞,IO多路復(fù)用

Nginx 這樣出眾寝贡,正是他采用了異步扒披,非阻塞,IO多路復(fù)用圃泡。

Nginx之前是單進(jìn)程的碟案。看下他的進(jìn)程颇蜡。1個master進(jìn)程价说,2個work進(jìn)程。

  1. $ pstree |grep nginx
  2. |-+= 81666 root nginx: master process nginx
  3. | |--- 82500 nobody nginx: worker process
  4. | \--- 82501 nobody nginx: worker process

每進(jìn)來一個request风秤,會有一個worker進(jìn)程去處理鳖目。但不是全程的處理,處理到什么程度呢缤弦?處理到可能發(fā)生阻塞的地方领迈,比如向上游(后端)服務(wù)器轉(zhuǎn)發(fā)request,并等待請求返回。那么狸捅,這個處理的worker不會這么傻等著衷蜓,他會在發(fā)送完請求后,注冊一個事件:“如果upstream返回了薪贫,告訴我一聲恍箭,我再接著干”。于是他就休息去了瞧省。這就是異步扯夭。此時,如果再有request 進(jìn)來鞍匾,他就可以很快再按這種方式處理交洗。這就是非阻塞IO多路復(fù)用。而一旦上游服務(wù)器返回了橡淑,就會觸發(fā)這個事件构拳,worker才會來接手,這個request才會接著往下走梁棠。這就是異步回調(diào)置森。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市符糊,隨后出現(xiàn)的幾起案子凫海,更是在濱河造成了極大的恐慌,老刑警劉巖男娄,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件行贪,死亡現(xiàn)場離奇詭異,居然都是意外死亡模闲,警方通過查閱死者的電腦和手機(jī)建瘫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尸折,“玉大人啰脚,你說我怎么就攤上這事∥淌冢” “怎么了拣播?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長收擦。 經(jīng)常有香客問我,道長谍倦,這世上最難降的妖魔是什么塞赂? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮昼蛀,結(jié)果婚禮上宴猾,老公的妹妹穿的比我還像新娘圆存。我一直安慰自己,他們只是感情好仇哆,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布沦辙。 她就那樣靜靜地躺著,像睡著了一般讹剔。 火紅的嫁衣襯著肌膚如雪油讯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天延欠,我揣著相機(jī)與錄音陌兑,去河邊找鬼。 笑死由捎,一個胖子當(dāng)著我的面吹牛兔综,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狞玛,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼软驰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了心肪?” 一聲冷哼從身側(cè)響起锭亏,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒙畴,沒想到半個月后贰镣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡膳凝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年碑隆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹬音。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡上煤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出著淆,到底是詐尸還是另有隱情劫狠,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布永部,位于F島的核電站独泞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏苔埋。R本人自食惡果不足惜懦砂,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荞膘,春花似錦罚随、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至屠升,卻和暖如春潮改,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弥激。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工进陡, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人微服。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓趾疚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親以蕴。 傳聞我的和親對象是個殘疾皇子糙麦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容