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