并行或同步迭代巨型阵列会更快吗?

时间:2014-08-08 20:05:10

标签: javascript concurrency parallel-processing

鉴于巨型阵列和单核心机器,并行或顺序迭代阵列会更快吗?假设没有工作作为迭代的一部分进行,它实际上只是迭代数组。

我的直觉说按顺序执行会更快,但我不能用我对操作系统和处理器的了解来证明这个答案。似乎必须以相同的方式完成相同数量的工作,但并行执行会给上下文切换带来额外的复杂性。

此问题的真实世界扩展是javascript的forEach方法。 Native forEach同步执行其回调

var a = [1,2,3,4,5,6...100000000000000];
a.foreach(function(number) {
    // do computationally expensive, synchronous operation eg lots of additions/multiplications
});
console.log('done iterating through for loop and doing all of the work')

为上述代码使用forEach的异步版本是否有利(特别是假设js只能使用单个内核)?

如果我们做同样的问题但是使用异步工作,一旦阻塞操作发生,forEach回调将变为异步。

var a = [1,2,3,4,5,6...100000000000000];
a.foreach(function(number) {
    // do asynchronous work, eg access to filesystem
    $.ajax({
        url: 'http://google.com',
        success: function() {
            console.log('suceeded for ' + number)
        })
});
console.log('done iterating through for loop but not with all async operations')

在这种情况下,使用forEach的异步版本会不会有利?似乎我们已经通过仅切换IO而在同步版本中更好地利用了CPU在我们甚至发起io之前切换。

2 个答案:

答案 0 :(得分:2)

只要您使用单核,就不会有任何优势进行某种并行操作。你是正确的,设置多个任务/线程会对每个任务/线程产生一定的开销。跨并行操作分时单核会在每个任务切换上产生开销。顺序迭代没有这样的开销。只有当你拥有多个内核时,才有可能对并行操作有所帮助。

现代CPU都是流水线的,大多数都是超标量引导。但尝试某种并行操作不会“打包管道”或填充超标量单位。我不知道那里的任何Javascript引擎都可以做到。

哦,只是为了记录,你最好使用for循环而不是foreach。原因很简单,foreach必须在每次传递时调用一个函数,即使它是一个匿名函数。调用函数会产生一定的开销。一个for循环,其中函数的内容被内联到循环体中,将没有这样的开销。这在其他论坛上已经引起广泛争论,但我自己的经验证实了这一事实。

答案 1 :(得分:1)

这完全取决于代码(很高兴你提供了这个)。因此,您的第一个问题的答案是 。对于第二个问题 取决于

如果代码是完全CPU绑定在单核心机器同步版本将更快一点。如果有任何IO绑定代码异步版本将在同一台机器上更快。因为访问IO不会处理CPU。

只有在多核机器上,如果cpu绑定代码在异步模式下运行,它们的运行速度会更快。 IO绑定代码仍将比其同步姐妹运行得更快。

这是一张夏日表,

type                                  cpu bound   io bound   mixed
-------------------------------------------------------------------
single-core synchronous               normal      slower     slower
single-core asynchronous              normal      faster     faster
multi-core synchronous                normal      slower     slower
multi-core asynchronous               faster      faster     faster

注意:

  1. 它假设在单次迭代中运行的所有代码不相互依赖。
  2. 在大多数实际使用案例中,我们要并行化的代码是IO和CPU的混合。
  3. 很难分开IO界限和CPU绑定部分