【问题标题】:big for loop hangs javascript engine大for循环挂起javascript引擎
【发布时间】:2014-10-11 06:51:08
【问题描述】:

最近在处理算法问题时,我发现了一个像这样的普通大 for 循环

var x = 1000000000000;
for (var i = 0; i <= x; i++) {}

可以挂起 javascript 引擎(在 node.js、Chrome 和 Firefox javascript 控制台上测试)。

实际上它正在运行,但是很慢。我尝试了几个x的值,当x = 1000000时有明显的延迟。

这种性能对于解释语言来说是正常的吗?

【问题讨论】:

  • 在 Node.js 中运行良好。不挂。
  • 当循环进行如此大量的迭代时,无论您使用什么语言,系统都肯定会挂起。但是,大多数解释器甚至都不会尝试运行您的循环,因为在循环之后从未使用过 i,并且循环什么也不做。
  • 您预计会发生什么?浏览器不执行抢先式多任务处理。引擎不是“挂”,而是“思考”。
  • 谢谢你们,现在我对循环有了一些了解——对于任何语言来说,这都是一项非常耗时的任务。

标签: javascript node.js google-chrome firefox for-loop


【解决方案1】:

您可以使用某种形式的loop unrolling,将循环分成块,例如使用Duffs device,或使用here 描述的机制。

该行为不仅限于解释型语言。循环将始终持续很长时间。例如在 c# 中尝试for (long n = 1000000000000; n &gt;= 0; n-=1) {}

最后,在(现代)浏览器中使用web workers 可能是可行的。这是我为另一个 SO 问题创建的 an example

【讨论】:

  • 你复制了我的链接;)
【解决方案2】:

这在任何语言中都会很慢。在这种情况下尤其明显,因为它会阻止您的 UI。 JavaScript 引擎执行单线程事件循环。您可以随时use web workers在后台执行慢速处理任务。

【讨论】:

    【解决方案3】:

    在实际情况下应该不会有问题,我在 MacBook Pro 笔记本电脑上进行了测试:

    • 1,000,000 次循环迭代
    • 每次迭代都会调用一个(简单)函数
    • 前几轮需要 2-3 毫秒(冷编译器)
    • 之后大约需要 0.5 毫秒(编译器优化热代码)

    如果您需要迭代超超级值,我会将其拆分为更小的垃圾并使用setTimeoutrequestAnimationFrame 将工作负载分散到不同的帧上,并且不会导致任何丢帧(帧有 ~ 16ms 完成所有工作)。

    console.clear();
    
    // options
    const start = true;
    const useFastTick = false; // 3ms per tick vs e.g 1s
    const interval = 1; // 1: once/sec, 2: twice/sec, etc
    const iterations = 1000000;
    
    function emptyFn() {}
    
    function argsFn(obj) {}
    
    function emptyFns() {
      for (let i = 0; i < iterations; i++) {
        if (i !== undefined && i !== null) emptyFn();
      }
    }
    
    function argsFns() {
      for (let i = 0; i < iterations; i++) {
        argsFn({a: 'hey', b: i, c: false});
      }
    }
    
    
    function tick() {
      const all0 = performance.now();
    
      const empty0 = performance.now();
      emptyFns();
      const empty1 = performance.now();
    
      const args0 = performance.now();
      argsFns();
      const args1 = performance.now();
    
      const all1 = performance.now();
    
      const all = (all1 - all0).toFixed(3);
      const empty = (empty1 - empty0).toFixed(3);
      const args = (args1 - args0).toFixed(3);
      log(all, empty, args);
    
      if (useFastTick) {
        setTimeout(tick, 3);
      } else {
        setTimeout(() => requestAnimationFrame(tick), 1000 * interval);
      }
    }
    
    if (start) requestAnimationFrame(tick);
    
    
    
    // log results to console
    function log(all, empty, args) {
      console.group(`${all}ms`);
      console.log(`Empty: ${empty}ms`);
      console.log(`Arrgs: ${args}ms`);
      console.groupEnd();
    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-03
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 2014-08-18
      • 1970-01-01
      相关资源
      最近更新 更多