如何使用并行子进程来执行"工作"在一个大阵列?

时间:2014-12-09 10:15:33

标签: javascript node.js concurrency parallel-processing child-process

我有很多数字。我想使用JavaScript / Node.js计算所有数字的总和。 (出于这个问题的目的,它是一个简单的总和;实际上我有一个更复杂和冗长的数学运算来执行)。

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

我的两个脚本如下:

index.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);

child.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.sendisn't meant to communicate large chunks of data,但我并不完全确定。

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

1 个答案:

答案 0 :(得分:2)

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

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

我建议你采用另一种方法。

  
      
  1. 创建子进程发送所有数据。

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

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

  6.   

注意:

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

  2.   
  3. 同样不要创建太少的子托,他们自己需要花费太多时间来处理给定的任务。

  4.   
  5. 你必须确保任何子进程在它自己进行治疗之前不会退出

  6.   

<强>优点:

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

随意询问您是否需要一些例子。