2013-05-30 39 views
2

我有一個非常簡單的實用程序腳本,我用JavaScript編寫了node.js,它讀取文件,進行一些計算,然後寫入輸出文件。在目前形式的源看起來是這樣的:我應該在node.js中的本地文件的同步等效項上使用異步文件IO方法嗎?

fs.readFile(inputPath, function (err, data) { 
    if (err) throw err; 
    // do something with the data 
    fs.writeFile(outputPath, output, function (err) { 
     if (err) throw err; 
     console.log("File successfully written."); 
    }); 
}); 

這工作得很好,但我不知道是否有在這種情況下,任何不利使用各種同步這些功能,而不是像這樣:

var data = fs.readFileSync(inputPath); 
// do something with the data 
fs.writeFileSync(outputPath, output); 
console.log("File successfully written."); 

對我來說,閱讀和理解比回調變得簡單得多。在這種情況下是否有任何理由使用前一種方法?

我意識到速度並不是一個問題,我用本地運行的這個簡單的腳本,但我有興趣瞭解它背後的理論。什麼時候使用異步方法有幫助,什麼時候沒有?即使在生產應用程序中,如果我只是在讀文件,然後等待執行下一個任務,是否有任何理由使用異步方法?

回答

6

重要的是當同步IO發生時,您的節點進程需要做什麼。在單個用戶在命令行運行簡單的shell腳本的情況下,同步IO是完全正確的,因爲如果你在執行異步IO,你所做的就是等待IO返回。

但是,在一個擁有多個用戶的網絡服務中,您絕對不能使用任何同步IO調用(這是類節點的全部點,所以請相信我)。這樣做會導致所有連接的客戶端停止處理,並且完成厄運。經驗法則:shell腳本:OK,網絡服務:verboten!

爲了進一步閱讀,我在this answer做了幾個類比。

基本上,當節點在網絡服務器中執行異步IO時,它可以要求操作系統執行許多操作:讀取幾個文件,進行一些數據庫查詢,發送一些網絡流量,並在等待異步IO準備好了,它可以在主事件線程中執行內存/ CPU的事情。使用這種體系結構,節點獲得相當不錯的性能/併發性。但是,當同步IO操作發生時,整個節點進程只會阻塞,並且什麼都不做。它只是等待。不能接收新的連接。沒有處理過程發生,沒有事件循環嘀嗒,沒有回調,沒有任何東西。只有1個同步操作會阻止所有客戶端的整個服務器。你一定不要這樣做。不管它有多快,或者類似的事情都沒有關係。這與本地文件系統或網絡請求無關。即使你花費10ms爲每個客戶端從磁盤讀取一個小文件,如果你有100個客戶端,客戶端100將等待整整一秒,而這個文件一次又一次被客戶端1-99讀取。

+1

這對我有意義,但你能詳細說明網絡服務點嗎? Node.js是單線程的,對嗎?如果是這樣,那麼如何使用與「異步」不同的同步IO調用?我意識到異步調用會放棄對其他用戶的主線程的控制權,但我不太清楚如何(在讀取本地文件時)他們將阻止線程同時投入單個客戶端。 –

1

異步代碼不會阻止執行流程,允許您的程序在等待操作完成時執行其他任務。

在第一個示例中,您的代碼可以繼續運行而無需等待寫入文件。在第二個例子中,代碼執行被「阻塞」直到寫入文件。這就是爲什麼同步代碼被稱爲「阻塞」,而異步代碼被稱爲「非阻塞」。