理解Node.js的事件輪詢
前言
總括 :
- 原文地址:理解Node.js的事件輪詢
- Node小應用:Node-sample
智者閱讀群書。亦閱歷人生
正文
Node.js的兩個基本概念
Node.js的第一個基本概念就是I/O操作開銷是巨大的:
所以,當前變成技術中最大的浪費來自於等待I/O操作的完畢。有幾種方法能夠解決性能的影響:
- 同步方式:按次序一個一個的處理請求。利:簡單。弊:不論什麽一個請求都能夠堵塞其它全部請求。
- 開啟新進程:每一個請求都開啟一個新進程。利:簡單;弊:大量的鏈接意味著大量的進程。
- 開啟新線程:每一個請求都開啟一個新線程。利:簡單,並且跟進程比。對系統內核更加友好。由於線程比進程輕的多;弊:不是全部的機器都支持線程,並且對於要處理共享資源的情況,多線程編程會非常快變得太過於復雜。
第二個基本概念是每一個連接都創建一個新線程是非常消耗內存的(比如:你能夠對照Nginx回憶一下Apache內存耗盡的情景)。
Apache是多線程的:它為每一個請求開啟一個新的線程(或者是進程,這取決於你的配置),當並發連接增多時。你能夠看看它是怎麽一點一點耗盡內存的。Nginx和Node.js不是多線程的,由於線程的消耗太“重”了。
它們兩個是單線程、基於事件的。這就把處理眾多連接所產生的線程/進程消耗給消除了。
單線程
確實僅僅有一個線程:你不能並行運行不論什麽代碼。比方:以下的“sleep”將會堵塞sever1秒鐘:
function sleep() {
var now = new Data().getTime();
while (new Date().getTime() < now + 1000) {
// do nothing
}
}
sleep();
但就我眼下學習階段而言,我認為好多人對於所謂的node單線程是有誤解的。實際上官方給出的“單線程”是具有誤導性的。所謂的單線程是指你的代碼僅僅運行在一個線程上(好多地方都叫它主線程。實際上Javascript的瀏覽器運行環境不也是這麽處理我們寫的Javascript代碼的嘛),而諸多任務的並行處理,就須要多線程了,例如以下圖:
如上圖,Node.js中的單線程之說指的就是這個主線程。這個主線程有一個循環結構。保持著整個程序(你寫的代碼)的運轉。
事件輪詢
事實上上面我們所說的維持主線程運行的循環這部分就是”事件輪詢”,它存在於主線程中,負責不停地調用開發人員編寫的代碼。但對開發人員是不可見的。so…開發人員編寫的代碼是如何被調用的呢?看下圖:
如上圖,異步函數在運行結束後。會在事件隊列中加入一個事件(遵循先進先出原則),主線程中的代碼運行完畢後(即一次循環結束),下一次循環開始就在事件隊列中”讀取”事件,然後調用它所相應的回調函數(所以回調函數的運行順序是不一定的)。假設開發人員在回調函數中調用了堵塞方法(比方上文中的sleep函數),那麽整個事件輪詢就會堵塞,事件隊列中的事件得不到及時處理。正由於這樣,nodejs中的一些庫方法均是異步的,也提倡用戶調用異步方法。
var fs = require(‘fs‘);
fs.readFile(‘hello.txt‘, function (err, data) { //異步讀取文件
console.log("read file end");
});
while(1)
{
console.log("call readFile over");
}
如上代碼,我們盡管使用了異步方法readfile讀取文件,但read file end
永遠不會輸出。由於代碼始終在while循環中。下一次事件輪詢始終沒法開始,也就沒法’讀取’事件隊列調用相應的回調函數了。
最後有一個Node-sample是博主平時積累的一些代碼。包括凝視,匯總成了一個小應用,還是能夠看到學習的蛛絲馬跡的。感興趣的您能夠看看。
後記
參考文章:
- Understanding the node.js event loop
- nodejs事件輪詢詳述
理解Node.js的事件輪詢