在node.js中协调并行执行

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

简单的顺序执行变成了嵌套的回调,这很容易(尽管有点复杂的写下来)。

但是并行执行怎么样? 假设你有三个任务A,B,C可以并行运行,当他们完成后,你想把他们的结果发送给任务D.

用叉/连接模型,这将是

  • 叉A
  • 叉B
  • 叉C
  • 加入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

    上一篇: Coordinating parallel execution in node.js

    下一篇: How do I parallelize a simple Python loop?