我是一名JS / node初学者,我试图在Javascript中解决“并发”问题。我觉得我现在对回调很满意,但我不认为这是我的方案中的方法。基本上我有重复的昂贵任务(worker
),我需要在main process
继续工作的同时逐一处理。这是一个最小的测试。
/*
* We have a worker function that does some expensive task, e.g., an
* I/O task or something else.
*/
worker = function ( jobId ) {
// It will take something between 1 and 2 seconds.
var runtime = Math.floor((Math.random() * 1000) + 1000);
console.log("started job #" + jobId + " (" + runtime + " ms)");
// Then the worker will do something for a while ...
setTimeout(
function() {
// .. and at some point it'll be finished.
console.log("finished job #" + jobId);
}, runtime
);
};
/*
* We obviously have a main process that meanwhile does other stuff
* like processed user interactions. In this case we call this until
* some artificial tickets are used.
*/
mainprocess = function (tickets) {
// Simulate some processing time ..
var runtime = Math.floor((Math.random() * 500));
setTimeout(
function() {
console.log("main process #" + tickets + " (" + runtime + " ms)");
if (tickets > 0) {
tickets--;
mainprocess(tickets);
}
}, runtime
);
}
// At some point in the code we create workers and we want to make sure
// they're processed in the *order of creation* and *one after another*
// without blocking the main process ...
for ( var i = 1; i <= 10; i++) {
worker(i);
};
// ... and the some other stuff will happen for a while!
mainprocess(10);
// ..
代码目前输出类似..
started job #1 (1751 ms)
started job #2 (1417 ms)
...
started job #9 (1050 ms)
started job #10 (1864 ms)
main process #10 (142 ms)
main process #9 (228 ms)
main process #8 (149 ms)
main process #7 (88 ms)
main process #6 (410 ms)
finished job #9
finished job #5
main process #5 (265 ms)
finished job #2
main process #4 (270 ms)
finished job #7
finished job #3
finished job #1
...
main process #1 (486 ms)
main process #0 (365 ms)
我真的不知道,如何更改代码,以便主进程将继续,而工作线程以创建顺序执行(目前只以正确的顺序启动)和一个接一个(目前全部并行)。那么期望的输出将是..
started job #1 (1384 ms)
main process #10 (268 ms)
main process #9 (260 ms)
main process #8 (216 ms)
main process #7 (93 ms)
main process #6 (160 ms)
main process #5 (269 ms)
main process #4 (44 ms)
finished job #1
started job #2 (1121 ms)
main process #3 (172 ms)
main process #2 (170 ms)
main process #1 (437 ms)
finished job #2
started job #3 (1585 ms)
main process #0 (460 ms)
finished job #3
started job #4 (1225 ms)
finished job #4
started job #5 (1300 ms)
finished job #5
任何帮助都将不胜感激。
答案 0 :(得分:1)
好的,我已经明白了。扩展和评论的代码使用 javascript的内置承诺,但您可以使用Q或Bluebird或任何其他节点兼容的promise库实现相同的功能。请注意,jquery $.Deferred
对象在节点环境中不可用。
/*
* We have a worker function that does some expensive task, e.g., an
* I/O task or something else.
*/
worker = function ( jobId ) {
// we need to put it into a new promise object
return new Promise(function(resolve, reject) {
// It will take something between 1 and 2 seconds.
var runtime = Math.floor((Math.random() * 1000) + 1000);
console.log("started job #" + jobId + " (" + runtime + " ms)");
// Then the worker will do something for a while ...
setTimeout(
function() {
// .. and at some point it'll be finished.
console.log("finished job #" + jobId);
// .. now we have to resolve the promise!!
resolve("resolved job #" + jobId);
}, runtime
);
});
};
/*
* We obviously have a main process that meanwhile does other stuff
* like processed user interactions. In this case we call this until
* some artificial tickets are used.
*/
mainprocess = function (tickets) {
// Simulate some processing time ..
var runtime = Math.floor((Math.random() * 500));
setTimeout(
function() {
console.log("main process #" + tickets + " (" + runtime + " ms)");
if (tickets > 0) {
tickets--;
mainprocess(tickets);
}
}, runtime
);
}
// create a sequence with a resolved promise
var sequence = Promise.resolve();
// At some point in the code we create workers and we want to make sure
// they're processed in the *order of creation* and *one after another*
// without blocking the main process ...
for ( var i = 1; i <= 10; i++) {
// create an IIFE so that the current "i" gets its own
// closure when it will be used later (otherwise all job ids
// would be "11" on invokation of the worker).
(function() {
var jobId = i;
// add a new promise after the previous promise resolved
sequence = sequence.then(
function(result) {
// handle result later
return worker(jobId);
// return just added the next promise to the chain!
},
function(err) {
// handle error later
}
);
})(); // END IIFE
};
// ... and the some other stuff will happen for a while!
mainprocess(10);
// ..
输出符合要求:
started job #1 (1384 ms)
main process #10 (268 ms)
main process #9 (260 ms)
main process #8 (216 ms)
main process #7 (93 ms)
main process #6 (160 ms)
main process #5 (269 ms)
main process #4 (44 ms)
finished job #1
started job #2 (1121 ms)
main process #3 (172 ms)
main process #2 (170 ms)
main process #1 (437 ms)
finished job #2
started job #3 (1585 ms)
main process #0 (460 ms)
finished job #3
started job #4 (1225 ms)
finished job #4
started job #5 (1300 ms)
finished job #5
...
我必须对以下文章给予高度赞赏,这些文章提供了见解:
答案 1 :(得分:0)
如果您希望主线程首先运行,然后按工作线程创建顺序运行,请将for循环放在您调用worker(i)的设置Timeout函数中,并给出大约1000ms的恒定延迟。然后,完成的作业也应该被给予1000ms的恒定延迟,以便它们按照它们的创建顺序执行。
查看链接:jsfiddle.net/som99/weq87xnd/2/