如何使用并行子进程在大型阵列上执行"work"?



我有一大堆数字。我想使用 JavaScript/Node.js 计算所有数字的总和。(就这个问题而言,这是一个简单的总和;实际上,我有一个更复杂和冗长的数学运算要执行(。

在单线程世界中,计算总和需要很长时间。为了更快地处理结果,我一直在尝试将工作委托给并行运行的多个子进程。每个子进程确定子数组的总和,所有内容都在父进程中汇总。

我的两个脚本如下:

索引.js

function computeSum(data) {
  var start = new Date();
  var sum = data.reduce(function(a, b) { return a + b; });
  console.log("Sum = %s, Time = %s ms", sum, new Date().getTime() - start.getTime());
}
function computeSumConcurrent(data) {
  var child_process = require("child_process");
  var os = require("os");
  var cpuCount = os.cpus().length;
  var subArraySize = data.length / cpuCount;
  var childProcessesFinished = 0;
  var start = new Date();
  var sum = 0;
  for (var i = 0; i < cpuCount; i++) {
    var childProcess = child_process.fork("child.js");
    childProcess.on("message", function(message) {
      sum += message.sum;
      childProcessesFinished++;
      if (childProcessesFinished == cpuCount) {
        console.log("Sum = %s, Time = %s ms", sum, new Date().getTime() - start.getTime());
        process.exit();
      }
    });
    childProcess.send({ subArray: data.slice(subArraySize * i, subArraySize * (i + 1)) });
  }
}
console.log("Populating array...");
var data = []
for (var i = 0; i < 50000000; i++) {
  data.push(Math.random());
}
console.log("Computing sum without using child processes...");
computeSum(data);
console.log("Computing sum using child processes...");
computeSumConcurrent(data);

孩子.js

process.on("message", function(message) {
  var sum = message.subArray.reduce(function(a, b) { return a + b; });
  process.send({ sum: sum });
  process.exit();
});

如果运行 index.js,则会发现并行总和非常慢。我认为这可能是由于childProcess.send,这并不意味着要传达大量数据,但我不完全确定。

那么这种事情的解决方案是什么?如何使并行总和比单线程总和更快?

为小型工作以及发送和接收消息创建子进程实际上可以增加持续时间或处理,因为发送和接收消息需要时间。

在你的代码中还有另一个问题,你实际上是在将子进程的工作与主进程本身分开,这不会让你的主进程免于工作,而只会增加它。

我建议你另一种方法。

  1. 创建一个子进程,向其发送所有数据。

  2. 让孩子自己创建其他孩子并给他们分配工作。 然后计算所有结果。

  3. 将最终结果发送给家长。

注意:

  1. 确保你不要创建太多的孩子,并给他们分配非常小的工作。 这只会让你发送和接收太多 消息,因此会延迟处理。

  2. 也不要创建太少的子分叉,它们本身需要太多时间来处理给定的任务。

  3. 您必须确保任何子进程都不会在它自己恢复的子进程之前退出

好处:

  1. 您的主流程不会忙于划分任务和计算结果。
  2. 分叉的大量子项将使你的任务在相对较短的时间内完成(我不说持续时间很短(

请随时询问您是否需要一些示例。

最新更新