big for循环挂起javascript引擎

big for loop hangs javascript engine

本文关键字:javascript 引擎 挂起 循环 for big      更新时间:2023-09-26

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

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

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

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

这种表现对于口译来说正常吗?

您可以使用某种形式的循环展开,将循环分解为块,例如使用Duffs设备,或者使用此处描述的机制。

这种行为并不局限于解释语言。循环将始终持续很长时间到很长时间。例如,请尝试c#中的for (long n = 1000000000000; n >= 0; n-=1) {}

最后,在(现代)浏览器中使用网络工作者可能是可行的。下面是我为另一个SO问题创建的示例。

这在任何语言中都会很慢。在这种情况下,它尤其引人注目,因为它阻塞了您的UI。JavaScript引擎执行单线程事件循环。您可以始终使用web工作者在后台执行处理速度较慢的任务。

我在MacBook Pro笔记本电脑上进行了测试:

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

如果您需要对超超巨型值进行迭代,我会将其拆分为更小的junk,并使用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();
}