理解Node.js異步非阻塞I/O與傳統線性阻塞IO的區別(轉)


阻塞I/O 程序執行過程中必然要進行很多I/O操作,讀寫文件、輸入輸出、請求響應等等。I/O操作時最費時的,至少相對於代碼來說,在傳統的編程模式中,舉個例子,你要讀一個文件,整個線程都暫停下來,等待文件讀完后繼續執行。換言之,I/O操作阻塞了代碼的執行,極大地降低了程序的效率。

下面是是一個C#讀文件的例子:

private string ReadTxtToStr(string filename)
{   
    //打開文件,打開期間其他代碼停止執行,直到完成打開后繼續執行代碼。   
    FileStream fs = File.Open(filename, FileMode.Open);    
    Console.WriteLine("我被打開文件阻塞了。");    
    StreamReader sr = new StreamReader(fs);    
    //讀取文件,讀取期間其他代碼停止執行,直到完成讀取后繼續執行代碼。    
    string str=sr.ReadToEnd();    
    Console.WriteLine("我被讀取文件阻塞了。");    
    return str;
}
在上述代碼中,兩個Console.WriteLine()雖然會被執行,但是卻被無辜地阻塞一段時間。理論上,如果讀取這個文件需要10秒,我們就浪費了10秒在I/O等待中(實際程序運行中有很大一部分時間是浪費在I/O等待上的),在碼農眼里這可是天文數字。 Having asynchronous I/O is good, because I/O is more expensive than most code and we should be doing something better than just waiting for I/O. 非阻塞I/O 理解了阻塞I/O,非阻塞I/O就好理解。非阻塞I/O是程序執行過程中,I/O操作不會阻塞程序的執行,也就是在I/O操作的同時,繼續執行其他代碼(這得益於Node的事件循環機制)。在I/O設備效率還遠遠低於CPU效率的時代,這種I/O模型(非阻塞I/O)為程序帶來的性能上的提高是非常可觀的。

好,下面感受一下怎么用Node.js實現非阻塞I/O,繼續讀文件,看碼:

var fs = require("fs");
fs.readFile("./testfile", "utf8", function(error, file) {  
     if (error) throw error;  
     console.log("我讀完文件了!");
});
console.log("我不會被阻塞!");
復制上面代碼保存為test.js,並在同一目錄下新建一個名為testfile的文件,用node命令運行test.js,你將看到以下輸出:

我不會被阻塞!

我讀完文件了!

這顯然不符合傳統的程序執行順序,注意,這就是Node.js的非阻塞I/O了。

首先解釋下面程序,如果你熟悉JavaScript,請忽略。

var fs = require("fs");
以上代碼:引入Node.js內置的File System文件系統模塊fs。require()相當與Java的import,C++的include。
fs.readFile("./testfile", "utf8", function(error, file) { 
    if (error) throw error; 
    console.log("我讀完文件了!");
});
 

以上代碼:進行I/O操作,給readFile綁定一個回調函數function(error,file){},並在讀取testfile完成后執行回調函數。期間,后面的代碼繼續執行,不受I/O阻塞。

這就是為什么先看到“我不會被阻塞!”而后看到“我讀完文件了!”的緣故。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM