当前位置: 首页 > 面试题库 >

在node.js中协调并行执行

阳念
2023-03-14
问题内容

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

简单的顺序执行变成嵌套的回调,这很容易(尽管有些麻烦以至于要写下来)。

但是并行执行如何?假设您有三个可以并行运行的任务A,B,C,当它们完成后,您要将其结果发送给任务D。

对于前叉/连接模型,这将是

  • fork A
  • fork B
  • fork C
  • join A,B,C, run 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或promises。只要考虑上面的答案,就可以很好地解释/说明async.parallel之类的事情。

为了完整起见,以下是您的处理方式async.parallel

var async = require('async');

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

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

使用promise,我们将其编写如下:

// Assuming A, B & C return a promise instead of accepting a callback

Promise.all([A,B,C]).then(D);


 类似资料:
  • 问题内容: 我正在尝试编写一个小型节点应用程序,该应用程序将搜索并解析文件系统上的大量文件。为了加快搜索速度,我们尝试使用某种类型的map reduce。该计划将是以下简化方案: Web请求带有搜索查询 启动3个进程,每个进程分配1000个(不同)文件 进程完成后,它将“返回”结果回到主线程 一旦所有进程完成,主线程将通过返回组合结果作为JSON结果来继续 我对此有以下疑问: 这在Node中可行吗

  • 问题内容: 我有类似的代码 它没有在node.js中按顺序执行,因此在执行结束时得到一个空数组。问题是它将先执行然后执行 我的代码中是否有任何错误或执行此操作的任何其他方式?谢谢! 问题答案: 您可能已经知道,事情在node.js中异步运行。因此,当您需要使事物按特定顺序运行时,您需要利用控件库或基本上自己实现。 我强烈建议您看一下async,因为它可以轻松地使您执行以下操作: 在这里看到的主要内

  • 问题内容: 在node.js中,我想找到一种方法来获取Unix终端命令的输出。有什么办法吗? 问题答案: 那就是我现在正在工作的项目中这样做的方式。 示例:检索git用户

  • 问题内容: 我可以在node.js中运行bash命令,如下所示: 如何获得该命令的退出代码(在此示例中)?我试过跑步 尽管如此,无论上一个命令的退出代码如何,它总是返回0。我想念什么? 问题答案: 这两个命令在单独的shell中运行。 要获取代码,您应该能够签入回调。 如果这不起作用,则需要添加一个事件处理程序 例如

  • 问题内容: 我有一个Node / Express路由功能,该功能在另一个模块中执行Redis调用。我想在一个节点模块中执行复杂的Redis功能,并发送一个简单的回调,说路由模块成功了。Redis调用会执行,但是我无法执行任何同步功能,即使从Redis调用中检索甚至是一个简单的true值。这是我的Redis函数: doctorDB.js 一切都为此目的而努力。现在,我希望将回调发送到Express路

  • 问题内容: 我正在使用python 2.7,我有一些看起来像这样的代码: 此处唯一的依赖项如下:dependent1需要等待任务1-3,Dependent2需要等待任务4-6,而dependent3需要等待依赖项1-2 …以下是可以的:首先运行全部6个任务并行,然后是前两个从属。 我希望尽可能多的任务并行运行,我已经在Google上搜索了一些模块,但是我希望避免使用外部库,并且不确定队列线程技术如