為什么 Event Loop 適合處理高并發(fā)?

在學(xué)習(xí) Node 的時(shí)候,一定會(huì)被告知 Node 是基于 Event Loop 的状勤,以及事件驅(qū)動(dòng)、事件隊(duì)列持搜、非阻塞 IO 等概念葫盼,最終得出一個(gè)結(jié)論:Node 非常適合 IO 密集型的應(yīng)用村斟,能夠以很少的資源消耗實(shí)現(xiàn)高并發(fā)。
但為什么 Event Loop 架構(gòu)可以實(shí)現(xiàn)較高的并發(fā)呢孩灯?這個(gè)問題我一直也不明白逾滥,于是我在網(wǎng)上查了一些文章寨昙,大概明白了一點(diǎn),便進(jìn)行整理尚卫,方便以后查看。

場(chǎng)景模擬

我們來模擬一個(gè)典型的請(qǐng)求-響應(yīng)模型:客戶端向服務(wù)器發(fā)起請(qǐng)求吱涉,服務(wù)端收到請(qǐng)求后對(duì)請(qǐng)求進(jìn)行處理,然后進(jìn)行數(shù)據(jù)庫(kù)讀取特石,最后將讀取的結(jié)果進(jìn)行響應(yīng)姆蘸。示例圖如下:


請(qǐng)求-響應(yīng)模型.png

在這個(gè)模型中芙委,會(huì)經(jīng)過三個(gè)階段:

  • 服務(wù)器收到請(qǐng)求并處理
  • 讀取數(shù)據(jù)庫(kù)
  • 服務(wù)器處理數(shù)據(jù)并響應(yīng)

在這三個(gè)階段中灌侣,第一個(gè)階段和最后一個(gè)階段會(huì)由 CPU 進(jìn)行計(jì)算,第二個(gè)階段則是 IO 操作牛柒,只占用極少的 CPU皮壁。
我們假定這三個(gè)階段各耗時(shí) 1ms,因此服務(wù)器處理每個(gè)請(qǐng)求所花的時(shí)間就為 3ms。
假如我們的服務(wù)器是單核 CPU畏腕,并只有一個(gè)線程茉稠,那么每秒鐘可以處理的請(qǐng)求約等于 333 個(gè)把夸,也就是服務(wù)器的 QPS 等于 333。
QPS 可以用來客觀描述服務(wù)器的并發(fā)能力膀篮,QPS 越大岂膳,服務(wù)器的并發(fā)能力越好。

單核單線程的情況

假定我們的服務(wù)器是單核單線程的谈截,那么其處理情況如下所示:


單核單線程.png

服務(wù)器收到了兩個(gè)請(qǐng)求:請(qǐng)求1和請(qǐng)求2。處理流程如下:

  1. 收到請(qǐng)求1燎潮,進(jìn)行處理
  2. 讀取數(shù)據(jù)庫(kù)扼倘,由于是單線程,CPU 需要等待 IO 讀取完成再進(jìn)行后面的操作
  3. 處理讀取到的數(shù)據(jù)爪喘,響應(yīng)客戶端
  4. 按上面的流程繼續(xù)處理請(qǐng)求2

單線程的瓶頸在于無法充分利用 CPU 資源腥放,在進(jìn)行 IO 讀取時(shí)绿语,CPU 實(shí)際上是處于空閑狀態(tài),必須等待 IO 讀取完成再進(jìn)行后面的處理种柑。對(duì)于每個(gè)請(qǐng)求聚请,CPU 都會(huì)有一個(gè)較大的等待時(shí)期稳其。在單線程模型下,服務(wù)器的 QPS 為 333煤傍。

單核多線程的情況

假定我們服務(wù)器是單核 CPU蚯姆,但是開啟了兩個(gè)線程洒敏,其處理情況如下所示:


單核多線程.png

采用單核多線程時(shí)凶伙,情況就不一樣了函荣,對(duì)于請(qǐng)求1和請(qǐng)求2链韭,將由兩個(gè)不同的線程進(jìn)行處理敞峭,流程如下:

  1. (線程1)收到請(qǐng)求1的請(qǐng)求進(jìn)行處理
  2. (線程1)請(qǐng)求1開始 IO 讀取旋讹,CPU 空閑
  3. (線程2)CPU 切換到請(qǐng)求2所在的線程,并進(jìn)行請(qǐng)求處理
  4. (線程2)請(qǐng)求2開始 IO 讀取沉迹,CPU 空閑
  5. (線程1)請(qǐng)求1的 IO 讀取完畢鞭呕,CPU 切換到請(qǐng)求1所在的線程宛官,處理數(shù)據(jù)并響應(yīng)客戶端,CPU 空閑
  6. (線程2)請(qǐng)求2的 IO 讀取完畢腋么,CPU 切換到請(qǐng)求2所在的線程亥揖,處理數(shù)據(jù)并響應(yīng)客戶端,CPU 空閑
  7. 按照上面的流程進(jìn)行請(qǐng)求3和請(qǐng)求4的處理

在多線程的模型下摧扇,由于 CPU 不用等待 IO 讀取完成扛稽,其核心得到了充分的利用庇绽,在這個(gè)模型下橙困,處理完兩個(gè)請(qǐng)求所耗時(shí)為 4ms耕餐,平均處理一個(gè)請(qǐng)求所耗時(shí)為 2ms肠缔,QPS 為 500哼转,并發(fā)能力比單線程模型好多了壹蔓。

多線程模型的問題

多線程模型最大的問題佣蓉,莫過于線程上下文切換所帶來的額外開銷了勇凭。上面展示的情況,是沒有上下文切換下的理想情況义辕,但在真實(shí)的環(huán)境下虾标,兩個(gè)線程間進(jìn)行切換,必定會(huì)產(chǎn)生開銷的灌砖,而且還不小璧函。因此上面的處理情況可能是這樣:


上下文切換開銷.png

因此,由于頻繁上下文切換造成的開銷基显,上面的多線程模型的并發(fā)能力比理想情況下要弱柳譬。

單線程異步 IO 的情況

在多線程模型中,通過使用線程切換续镇,避免了 CPU 因等待 IO 操作的閑置美澳,最大程度上利用了 CPU 資源,但是線程間的頻繁上下文切換也會(huì)產(chǎn)生很大的開銷摸航,同樣會(huì)增加服務(wù)器的壓力制跟。因此,要想避免線程上下文切換的帶來的開銷雨膨,就只有使用單線程。
在使用單線程的情況下排监,能否實(shí)現(xiàn)非阻塞的 IO 呢?


單線程異步IO.png

上面就是一個(gè)單線程非阻塞 IO 的模型谷暮,處理請(qǐng)求時(shí)的流程如下:

  1. 收到請(qǐng)求1腾夯,開始處理請(qǐng)求
  2. 進(jìn)行請(qǐng)求1的 IO 讀取竟秫,并注冊(cè)一個(gè)回調(diào)函數(shù)(處理數(shù)據(jù)并響應(yīng)客戶端),同時(shí)線程不阻塞馒稍,繼續(xù)處理請(qǐng)求2
  3. 進(jìn)行請(qǐng)求2的 IO 讀取如输,并注冊(cè)一個(gè)回調(diào)函數(shù)(處理數(shù)據(jù)并響應(yīng)客戶端)澳化,同時(shí)線程不阻塞,繼續(xù)處理剩下的請(qǐng)求
  4. 請(qǐng)求處理結(jié)束后,依次執(zhí)行 IO 讀取是注冊(cè)的回調(diào)函數(shù)(處理數(shù)據(jù)并響應(yīng)客戶端)希痴,完成處理

假設(shè)服務(wù)器只接受到兩個(gè)請(qǐng)求:請(qǐng)求1和請(qǐng)求2甥厦,按照上面的流程圖舶赔,處理這兩個(gè)請(qǐng)求的時(shí)間為 4ms,平均每個(gè)請(qǐng)求用時(shí) 2ms,此時(shí)服務(wù)器的 QPS 為 500桶略。由于是單線程運(yùn)行,沒有頻繁上下文切換帶來的開銷鹅心,因此這個(gè)單線程異步 IO 的模型比多線程模型占用的資源更少宙暇,對(duì)服務(wù)器配置要求更低用押。同時(shí),從流程圖也可以看到,這種架構(gòu)具備很大的吞吐能力,十分適合 IO 密集型的應(yīng)用夹纫。

總結(jié)

本文對(duì)幾種常見的任務(wù)處理模型:?jiǎn)尉€程模型、多線程模型、單線程非阻塞 IO 模型進(jìn)行了對(duì)比素标,依據(jù)是應(yīng)用這些模型時(shí)的服務(wù)器 QPS 值退腥,得出的結(jié)論是單線程非阻塞 IO 模型具備較強(qiáng)的并發(fā)處理能力享潜,且占用更少的資源。
Node 的 Event Loop 基于這種單線程非阻塞 IO 模型,因此具備強(qiáng)大的并發(fā)能力,適合 IO 密集型的應(yīng)用(如游戲缩擂、電商秒殺活動(dòng)等)博脑。

附:參考資料
Node.js為什么快
JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop
【樸靈評(píng)注】JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop
理解Node.js的event loop

完叉趣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子割以,更是在濱河造成了極大的恐慌跟伏,老刑警劉巖勘高,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件建蹄,死亡現(xiàn)場(chǎng)離奇詭異劲腿,居然都是意外死亡花椭,警方通過查閱死者的電腦和手機(jī)袋倔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門嘱根,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冈爹,“玉大人憋肖,你說我怎么就攤上這事怎炊∨什伲” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)瑞筐。 經(jīng)常有香客問我峭范,道長(zhǎng)胚迫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任拱雏,我火速辦了婚禮蒲赂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘是尖。我一直安慰自己,他們只是感情好兜辞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布足绅。 她就那樣靜靜地躺著氢妈,像睡著了一般加缘。 火紅的嫁衣襯著肌膚如雪柄延。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天昭躺,我揣著相機(jī)與錄音砚哗,去河邊找鬼。 笑死砰奕,一個(gè)胖子當(dāng)著我的面吹牛频祝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脆淹,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼常空,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了盖溺?” 一聲冷哼從身側(cè)響起漓糙,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烘嘱,沒想到半個(gè)月后昆禽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝇庭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年醉鳖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哮内。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盗棵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出北发,到底是詐尸還是另有隱情纹因,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布琳拨,位于F島的核電站瞭恰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏狱庇。R本人自食惡果不足惜惊畏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望密任。 院中可真熱鬧颜启,春花似錦、人聲如沸批什。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至乳规,卻和暖如春形葬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暮的。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工笙以, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冻辩。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓猖腕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親恨闪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子倘感,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345