![](/img/trans.png)
[英]Nodejs how to handle multiple parallel requests incase of blocking process
[英]NodeJS promise blocking requests
我對為什么諾言阻止節點應用程序請求感到困惑。
這是我的簡化代碼:
var express = require('express');
var someModule = require('somemodule');
app = express();
app.get('/', function (req, res) {
res.status(200).send('Main');
});
app.get('/status', function (req, res) {
res.status(200).send('Status');
});
// Init Promise
someModule.doSomething({}).then(function(){},function(){}, function(progress){
console.log(progress);
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s in %s environment',host, port, app.get('env'));
});
和模塊:
var q = require('q');
function SomeModule(){
this.doSomething = function(){
return q.Promise(function(resolve, reject, notify){
for (var i=0;i<10000;i++){
notify('Progress '+i);
}
resolve();
});
}
}
module.exports = SomeModule;
顯然,這是非常簡化的。 Promise函數執行的工作可能需要5到30分鍾,並且僅在服務器啟動時才能運行。 該Promise函數中沒有異步操作。 它只是大量的數據處理,循環等。
我不會馬上就可以提出要求。 因此,我期望的是在運行服務器時,我可以立即轉到127.0.0.1:3000
並查看Main
和其他請求。
最終,我想通過訪問/status
查看該任務的進度,但是我確定一旦服務器按預期工作,我就可以使該工作正常進行。
目前,當我打開/
它會一直掛起,直到答應工作完成。
顯然我在做錯事...
node.js中Javascript的主線程是單線程。 因此,如果您執行某個受處理器限制的巨型循環,那么它將占用一個線程,並且其他的JS將不會在node.js中運行,直到完成一個操作為止。
因此,當您致電:
someModule.doSomething()
並且這都是同步的,那么它直到執行完畢才返回,因此緊接着doSomething()
方法返回的代碼行才執行。 而且,正如您了解的那樣,將諾言與同步CPU跳轉代碼一起使用根本無法解決您的問題。 如果它是同步的且受CPU限制,則將需要很長時間才能運行其他任何東西。
如果循環中涉及I / O(例如磁盤I / O或網絡I / O),那么就有機會使用異步I / O操作並使代碼無阻塞。 但是,如果不是這樣,而這只是大量的CPU工作,那么它將阻塞直到完成,並且不會運行其他代碼。
您改變的機會是:
在另一個進程中運行占用CPU的代碼。 創建一個作為子進程運行的單獨程序,您可以將其傳遞給輸入或從中獲取輸出,或者創建一個單獨的服務器,然后向其發出異步請求。
將非阻塞工作分成多個塊,您一次執行100ms的塊工作,然后使處理器返回事件循環(使用setTimeout()
東西來允許事件隊列中的其他事件得到服務並在運行之前運行)選擇並運行下一個工作塊,您將看到在不阻塞UI的情況下遍歷數組的最佳方法,以獲取有關如何對同步工作進行分塊的想法。
例如,您可以對當前循環進行分塊。 這需要長達100毫秒的周期,然后中斷執行,使其他事物有運行的機會。 您可以將循環時間設置為任意時間。
function SomeModule(){
this.doSomething = function(){
return q.Promise(function(resolve, reject, notify){
var cntr = 0, numIterations = 10000, timePerSlice = 100;
function run() {
if (cntr < numIterations) {
var start = Date.now();
while (Date.now() - start < timePerSlice && cntr < numIterations) {
notify('Progress '+cntr);
++cntr;
}
// give some other things a chance to run and then call us again
// setImmediate() is also an option here, but setTimeout() gives all
// other operations a chance to run alongside this operation
setTimeout(run, 10);
} else {
resolve();
}
}
run();
});
}
}
如果您的任務是IO綁定,請使用process.nextTick
。 如果您的任務是與CPU綁定,那么異步調用將無法提供很多性能。 在這種情況下,您需要將任務委托給另一個進程。 一個示例解決方案是生成一個子進程,進行工作並將完成后的結果通過管道傳遞給父進程。
有關更多信息,請參見nodejs.org/api/child_process.html。
如果您的應用程序需要經常執行此操作,那么派生許多子進程會很快成為資源浪費-每次您分叉時,都會將一個新的V8進程加載到內存中。 在這種情況下,最好使用像Node自己的Cluster這樣的多處理模塊之一。 該模塊可輕松創建主工作流程,並在主工作流程之間進行通信,並且可以消除代碼中的許多復雜性。
另請參閱相關問題: Node.js-將大對象發送到child_process很慢
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.