學(xué)習(xí)nodejs時(shí)汹桦,看到它的簡(jiǎn)介說(shuō)它是采用異步I/O與事件驅(qū)動(dòng)的架構(gòu)設(shè)計(jì),搜了很多關(guān)于同步I/O和異步I/O的資料感覺(jué)也沒(méi)咋看明白鉴裹,直到看了nodejs開(kāi)發(fā)指南這本書(shū)第3.2節(jié)才對(duì)異步式I/O有了清晰地認(rèn)識(shí)舞骆。
阻塞I/O(同步I/O)
線程在執(zhí)行中如果遇到磁盤(pán)讀寫(xiě)或網(wǎng)絡(luò)通信(統(tǒng)稱為 I/O 操作), 通常要耗費(fèi)較長(zhǎng)的時(shí)間径荔,這時(shí)操作系統(tǒng)會(huì)剝奪這個(gè)線程的 CPU 控制權(quán)督禽,使其暫停執(zhí)行,同時(shí)將資源讓給其他的工作線程总处,這種線程調(diào)度方式稱為阻塞狈惫。當(dāng) I/O 操作完畢時(shí),操作系統(tǒng) 將這個(gè)線程的阻塞狀態(tài)解除鹦马,恢復(fù)其對(duì)CPU的控制權(quán)胧谈,令其繼續(xù)執(zhí)行。這種 I/O 模式就是通常的阻塞式 I/O(同步I/O) 菠红。
非阻塞I/O(異步I/O)
非阻塞式 I/O(異步I/O) 則針對(duì)所有 I/O 操作不采用阻塞的策略。當(dāng)線程遇到 I/O 操作時(shí)难菌,不會(huì)以阻塞的方式等待 I/O 操作 的完成或數(shù)據(jù)的返回试溯,而只是將 I/O 請(qǐng)求發(fā)送給操作系統(tǒng),繼續(xù)執(zhí)行下一條語(yǔ)句郊酒。當(dāng)操系統(tǒng)完成 I/O 操作時(shí)遇绞,以事件的形式通知執(zhí)行 I/O 操作的線程,線程會(huì)在特定時(shí)候處理這個(gè) 事件燎窘。為了處理異步 I/O摹闽,線程必須有事件循環(huán),不斷地檢查有沒(méi)有未處理的事件褐健,依次予以處理付鹿。
多線程同步I/O
阻塞模式下,一個(gè)線程只能處理一項(xiàng)任務(wù)蚜迅,要想提高吞吐量必須通過(guò)多線程舵匾,一個(gè)線程阻塞時(shí)還有其他線程在工作,多線程可以讓 CPU 資源不被阻塞中的線程浪費(fèi)谁不。
單線程異步I/O
單線程異步I/O維護(hù)一個(gè)事件隊(duì)列坐梯,程序在執(zhí)行時(shí)進(jìn)入事件循環(huán)等待下一個(gè)事件到來(lái),每個(gè)異步式 I/O 請(qǐng)求完成后會(huì)被推送到事件隊(duì)列刹帕,等待程序進(jìn)程進(jìn)行處理吵血。在這個(gè)模式下谎替,一個(gè)線程永遠(yuǎn)在執(zhí)行計(jì)算操作,這個(gè)線程所使用的 CPU 核心利用率永遠(yuǎn)是 100%蹋辅。
nodejs采用單線程異步I/O的優(yōu)勢(shì)與弊端
優(yōu)勢(shì)
從多線程同步I/O與單線程異步I/O的兩個(gè)示例圖來(lái)看钱贯,它們完成N個(gè)事件的時(shí)間理論上是一樣的,不同的是晕翠,異步式 I/O 少了多線程的開(kāi)銷喷舀,對(duì)操作系統(tǒng)來(lái)說(shuō),創(chuàng)建一個(gè)線程的代價(jià)是十分昂貴的淋肾, 需要給它分配內(nèi)存硫麻、列入調(diào)度,同時(shí)在線程切換的時(shí)候還要執(zhí)行內(nèi)存換頁(yè)樊卓,CPU 的緩存被清空拿愧,切換回來(lái)的時(shí)候還要重新從內(nèi)存中讀取信息,而單線程異步I/O可以有效避免這種頻繁的上下文切換碌尔。
弊端
異步式編程的缺點(diǎn)在于不符合人們一般的程序設(shè)計(jì)思維浇辜,容易讓控制流變得晦澀難懂,給編碼和調(diào)試都帶來(lái)不小的困難唾戚。