首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在node.js中协调并行执行

在node.js中协调并行执行
EN

Stack Overflow用户
提问于 2011-01-08 09:21:24
回答 7查看 36.8K关注 0票数 79

node.js的事件驱动编程模型使得协调程序流变得有些棘手。

简单的顺序执行被转换为嵌套回调,这很容易(尽管写起来有点复杂)。

但是并行执行呢?假设您有三个可以并行运行的任务A、B、C,当它们完成后,您希望将它们的结果发送到任务D。

对于fork/join模型,这将是

  • fork A
  • fork B
  • fork C
  • join A,B,C,run D

<代码>F29

我如何在node.js中编写它?有什么最佳实践或食谱吗?我是不是每次都要用hand-roll a solution,或者有没有带帮助器的库?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2011-01-08 09:54:30

在node.js中没有什么是真正并行的,因为它是单线程的。但是,可以安排多个事件并以您无法预先确定的顺序运行。而像数据库访问这样的一些事情实际上是“并行的”,因为数据库查询本身是在单独的线程中运行的,但在完成后又被重新集成到事件流中。

那么,如何在多个事件处理程序上调度回调呢?这是浏览器端javascript动画中常用的一种技术:使用变量来跟踪完成。

这听起来像是一个黑客,它确实是,而且它听起来可能很混乱,留下一堆全局变量来做跟踪,如果用一种较小的语言就会是这样。但在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()函数已经可以使用闭包将参数传递给异步函数:

代码语言:javascript
复制
fork([
  function(callback){ A(1,2,callback) },
  function(callback){ B(1,callback) },
  function(callback){ C(1,2,callback) }
],D);

剩下的唯一要做的事情就是将A、B、C的结果累加,并将它们传递给D。

更多额外的答案:

我无法抗拒。吃早餐的时候一直在想这个问题。下面是一个累积结果的fork()实现(通常作为参数传递给回调函数):

代码语言:javascript
复制
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中的用法示例:

代码语言:javascript
复制
// 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或promises。只需考虑上面的答案,就可以很好地解释/说明像async.parallel这样的东西是如何工作的。

为了完整起见,下面是如何使用async.parallel完成此操作的

代码语言:javascript
复制
var async = require('async');

async.parallel([A,B,C],D);

请注意,async.parallel的工作方式与我们上面实现的fork函数完全相同。主要区别在于,根据node.js约定,它将错误作为第一个参数传递给D,并将回调作为第二个参数传递。

使用promises,我们可以这样写:

代码语言:javascript
复制
// Assuming A, B & C return a promise instead of accepting a callback

Promise.all([A,B,C]).then(D);
票数 128
EN

Stack Overflow用户

发布于 2011-09-24 13:23:11

我相信"async“模块现在提供了这种并行功能,并且与上面的fork函数大致相同。

票数 10
EN

Stack Overflow用户

发布于 2012-02-20 12:47:09

futures模块有一个名为join的子模块,我想使用它:

将异步调用连接在一起,类似于pthread_join对线程的工作方式。

自述文件展示了一些使用freestyle或使用Promise模式的future子模块的很好的例子。文档中的示例:

代码语言:javascript
复制
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);
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4631774

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档