前面啰啰嗦嗦地一直在強調IO密集型,其實是在強調node.js的強項。相應的,它的短板就是CPU密集型的請求。道理很簡單,javascript不會并發,只能一個請求完成后才能處理其他請求。一個請求處理的時間越長,其他請求等待的時間越長。同一時間只會有一個請求被處理,并發性能很低。
話說到這兒,我想申明一點:node.js不應該被阻塞;能異步處理的方法異步處理(如使用fs.readFile(),而非fs.syncReadFile()fs.readFileSync()方法)。
node中不能阻塞,并不代表node外不能阻塞。前面我們有講到fibers,現在,我們就來嘗試在fibers中實現阻塞。就以處理一個http請求為例吧:
代碼如下:
var Fiber = require('fibers');
var http = require("http");
Fiber(function () {
var httpFiber = Fiber.current;
var html = "";
http.get("http://www.baidu.com", function (res) {
var dataFiber = Fiber.current;
res.on("data", function (data) {
html += data;
});
res.on("end", function (data) {
httpFiber.run();
});
});
Fiber.yield();
console.log(html);
}).run();
yield()、 run()這兩個方法還不了解的同學,請自行查閱《fibers in node》。
fibers的運行并不在node進程中,所以在fibers內部實現阻塞對node整體的性能并沒有影響。而且實現起來也是相當容易,只需要在想阻塞的時候,把fiber yield掉。需要繼續運行,則執行 run()恢復fiber。在上面的例子中,我們希望當http.get請求發起時阻塞當前程序,當所有數據接收完成時,恢復程序。于是我們在調用http.get后使用 Fiber.yield()中斷此fiber。在對response的監聽中,如果觸發 end事件表明數據傳輸完成,于是在 end的回調函數中,調用 Fiber.current.run()恢復fiber,這樣,后續的代碼就以同步的方式拿到http.get請求的數據。
上面的示例只是提供一種思路。如果對這種思路進行一些抽象封裝,比如說,對有接受回調函數為參數的異步方法進行一步柯里化,在調用后中斷,并劫持回調函數,以恢復程序的代碼為回調函數。獲取異步數據后,再程序觸發預定的回調函數,這樣基本能實現異步方法同步化。這段說得比較亂,基本上就是 fibers/future的實現思路,如果有興趣,請參考其源代碼。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com