1. 程式人生 > >理解Node.js的事件輪詢

理解Node.js的事件輪詢

地址 and func down 先進先出 異步 不可 call javascrip

前言

總括

  • 原文地址:理解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的事件輪詢