在node.js中协调并行执行
node.js的事件驱动编程模型使协调程序流程有点棘手。
简单的顺序执行变成了嵌套的回调,这很容易(尽管有点复杂的写下来)。
但是并行执行怎么样? 假设你有三个任务A,B,C可以并行运行,当他们完成后,你想把他们的结果发送给任务D.
用叉/连接模型,这将是
我如何在node.js中编写它? 有没有最佳做法或食谱? 我是否每次都必须手动推出解决方案,或者是否有一些图书馆有助手?
因为它是单线程的,所以在node.js中没有真正的并行。 但是,可以安排多个事件并按照事先不能确定的顺序运行。 而像数据库访问这样的事情实际上是“并行”的,因为数据库查询本身是在单独的线程中运行的,但是在完成时重新集成到事件流中。
那么,你如何安排多个事件处理程序的回调? 那么,这是浏览器端JavaScript中动画中常用的一种技术:使用变量来追踪完成。
这听起来像是一种骇人听闻的事情,而且听起来可能会很麻烦,留下一堆全局变量来进行跟踪,而且会用更少的语言。 但在JavaScript中,我们可以使用闭包:
function fork (async_calls, shared_callback) {
var counter = async_calls.length;
var callback = function () {
counter --;
if (counter == 0) {
shared_callback()
}
}
for (var i=0;i<async_calls.length;i++) {
async_calls[i](callback);
}
}
// usage:
fork([A,B,C],D);
在上面的例子中,我们通过假定异步和回调函数不需要参数来保持代码简单。 您当然可以修改代码以将参数传递给异步函数,并让回调函数累积结果并将其传递给shared_callback函数。
附加答案:
实际上,即使这样, fork()
函数也可以使用闭包将参数传递给异步函数:
fork([
function(callback){ A(1,2,callback) },
function(callback){ B(1,callback) },
function(callback){ C(1,2,callback) }
],D);
剩下唯一要做的就是积累来自A,B,C的结果并将它们传递给D.
更多附加答案:
我无法抗拒。 在早餐时保持思考。 下面是fork()
的一个实现,它累积结果(通常作为参数传递给回调函数):
function fork (async_calls, shared_callback) {
var counter = async_calls.length;
var all_results = [];
function makeCallback (index) {
return function () {
counter --;
var results = [];
// we use the arguments object here because some callbacks
// in Node pass in multiple arguments as result.
for (var i=0;i<arguments.length;i++) {
results.push(arguments[i]);
}
all_results[index] = results;
if (counter == 0) {
shared_callback(all_results);
}
}
}
for (var i=0;i<async_calls.length;i++) {
async_calls[i](makeCallback(i));
}
}
这很简单。 这使fork()
相当普遍的用途,可用于同步多个非同类事件。
Node.js中的示例用法:
// Read 3 files in parallel and process them together:
function A (c){ fs.readFile('file1',c) };
function B (c){ fs.readFile('file2',c) };
function C (c){ fs.readFile('file3',c) };
function D (result) {
file1data = result[0][1];
file2data = result[1][1];
file3data = result[2][1];
// process the files together here
}
fork([A,B,C],D);
更新
这个代码是在诸如async.js或各种基于promise的库之类的库之前编写的。 我想相信async.js受此启发,但我没有任何证据。 无论如何..如果你今天想这样做看看async.js或承诺。 只要考虑上面的答案,就可以很好地解释/说明诸如async.parallel的工作。
我相信现在“异步”模块提供了这种并行功能,并且与上面的fork函数大致相同。
期货模块有一个我喜欢使用的名为join的子模块:
类似于pthread_join
对线程起作用的方式将异步调用联合在一起。
自述文件展示了使用自由式或使用Promise模式使用未来子模块的一些很好的例子。 来自文档的示例:
var Join = require('join')
, join = Join()
, callbackA = join.add()
, callbackB = join.add()
, callbackC = join.add();
function abcComplete(aArgs, bArgs, cArgs) {
console.log(aArgs[1] + bArgs[1] + cArgs[1]);
}
setTimeout(function () {
callbackA(null, 'Hello');
}, 300);
setTimeout(function () {
callbackB(null, 'World');
}, 500);
setTimeout(function () {
callbackC(null, '!');
}, 400);
// this must be called after all
join.when(abcComplete);
链接地址: http://www.djcxy.com/p/79381.html