內(nèi)容
node的單線程異步io模型是這樣設(shè)計(jì)的:
(1)執(zhí)行異步方法鹊奖,將異步的任務(wù)交給內(nèi)核密任,不帶數(shù)據(jù)返回刁岸;
(2)繼續(xù)執(zhí)行其他操作
(3)事件循環(huán)拿到異步操作完成的信號(hào)或者事件后独郎,執(zhí)行異步方法中的回調(diào)函數(shù)
如圖
這個(gè)設(shè)計(jì)是怎么實(shí)現(xiàn)的呢液南? 需要幾個(gè)幫手壳猜,事件循環(huán),觀察者滑凉,請(qǐng)求對(duì)象统扳,線程池,以下拿 fs.open 舉例子:
fs.open('<directory>', 'r+', (err, fd) => {
// ...
});
我們使用fs.open, 即調(diào)用了lib中fs.js畅姊, 然后fs.js調(diào)用了c++核心模塊node_file.cc, 然后判斷判斷平臺(tái)來(lái)采取不同的操作
判斷好平臺(tái)后咒钟,node會(huì)創(chuàng)建一個(gè)請(qǐng)求對(duì)象,請(qǐng)求對(duì)象會(huì)保存當(dāng)前所有的狀態(tài)和回調(diào)函數(shù)若未,當(dāng)前場(chǎng)景下的請(qǐng)求對(duì)象是 FSReqWrap朱嘴。
請(qǐng)求對(duì)象會(huì)送入IO線程池等待執(zhí)行,執(zhí)行完畢后會(huì)將執(zhí)行結(jié)果存放在請(qǐng)求對(duì)象的result屬性上粗合,然后通知操作系統(tǒng)當(dāng)前對(duì)象操作已完成萍嬉,并歸還線程給線程池。
事件循環(huán)中的IO觀察者會(huì)在每輪tick中檢查線程池中是否有執(zhí)行完成的請(qǐng)求隙疚,有的話壤追,取出對(duì)應(yīng)的請(qǐng)求對(duì)象的回調(diào)函數(shù),并取出result作為參數(shù)(這里對(duì)應(yīng)的是err 或 fd)供屉,然后執(zhí)行行冰。
至此溺蕉,一個(gè)異步IO就完成了。
寫在后面
首先來(lái)理解下為什么node要采用單線程異步io悼做。
如果是多線程疯特,會(huì)面臨各線程狀態(tài)同步,鎖的問(wèn)題贿堰。如果是單線程同步阻塞辙芍,在多并發(fā)的情況下等待的時(shí)間會(huì)很長(zhǎng)啡彬,而采用上述設(shè)計(jì)模型的單線程異步io能很好的規(guī)避所提的這兩個(gè)問(wèn)題羹与。
另外,javascript在服務(wù)器端編程領(lǐng)域上沒(méi)有歷史包袱庶灿,加上前端開(kāi)發(fā)者對(duì)異步編程都比較熟悉纵搁,所以node就采用了單線程異步io的模型。
其次往踢,node是多線程的腾誉,單線程是指js是單線程執(zhí)行的。
node是由一個(gè)js執(zhí)行線程和多個(gè)阻塞線程組成的線程池構(gòu)成的峻呕。io異步中的一個(gè)重要幫手就是事件循環(huán)利职,事件循環(huán)是典型的生產(chǎn)者消費(fèi)者模型,在windows下基于IOCP創(chuàng)建瘦癌,在Linux下基于多線程創(chuàng)建(libuv自行實(shí)現(xiàn))猪贪。
參考鏈接
《深入淺出nodejs》第三章