0

在 JavaScript Patterns Stoyan Stefanov 一书中,他声称 JavaScript 中循环的常见方式

for (i = 0, max = myarray.length; i < max; i++) {
// do something with myarray[i]
}

可以通过使用此模式进行优化

for (i = myarray.length; i--;) {
// do something with myarray[i]
}

我发现这很有趣,所以我决定在现实世界中测试它,将该技术应用于性能密集型循环,该循环在这篇关于使用 canvas 进行像素操作的博客文章中展示。可以在此处查看将常规代码与“优化”代码进行比较的基准。

有趣的是,所谓的优化循环实际上比 Opera 和 Firefox 中的常规循环方式慢。这是为什么?

4

3 回答 3

3

这种微优化的有效性总是非常有限。很有可能,VM 实现包括对“常用方式”的优化,这些优化超出了您在语言级别上可以做的事情。

这就是为什么微优化通常是浪费时间的原因。初学者往往会沉迷于它们并最终编写出难以维护且速度缓慢的代码。

于 2012-09-03T11:32:05.250 回答
1

首先,我看不出为什么第二个应该比第一个快得多。与零比较与与另一个数字比较之间的差异可能会在编译代码中的极其紧密的循环中产生差异,但即使在大多数情况下,它也可能是一种货物崇拜选择(如果你不这样做,请阅读 Richard Feyman 的Cargo Cult Science )没有得到参考,如果没有别的,它是一个很好的阅读,也有不止几次类似的倾向将曾经运行良好的东西复制到没有真正理由认为它会有所帮助的情况下,在编程中)。

我可以看到以下内容变慢:

for (i = 0; i < myarray.length; i++) {
// do something with myarray[i]
}

但是我也可以看到它并没有变慢,如果引擎为你优化了提升长度检查,或者实现是这样的,检查长度和检查变量无论如何都是差不多的成本。

我还可以看到您给出的那个或第一个代码示例,或者两者都是给定脚本引擎优化的东西 - 毕竟这是 js 中非常常见的习语,并且固有地涉及循环,所以这将是一个明智的试图在脚本引擎中检测和优化的东西。

但是,除了这些猜想之外,我们真的不能说什么,除了“因为在那个引擎中一个比另一个在那个引擎中工作得更好,这就是为什么”没有达到低于 javascript 的级别并检查引擎的实现。您的结果表明每个引擎的答案都不相同(毕竟,一个引擎确实更符合您的预期)。

现在,值得注意的是,在每种情况下,结果都非常接近。如果您发现只有一两个当前相当流行的浏览器,而更改确实优化了,那么它仍然值得。

如果您对它是否值得,或者只是一个假设感兴趣,您可以尝试获取 Netscape 2(毕竟第一个 javascript 浏览器)的副本,并运行一些代码来测试该方法在上面。

编辑:如果您确实尝试了这种实验,另一种方法是故意尝试错误的循环,使数组边界超出一个。引擎的一种可能的优化是意识到您正在遍历数组,并检查一次您将在哪里结束以超出范围。如果是这样,如果你最终会出错,你可能会得到不同的结果。

于 2012-09-03T11:52:34.057 回答
1

尝试优化循环的大多数方法都来自 C,而当时编译器更简单,处理器一个接一个地执行一条指令。

现代处理器运行代码的方式非常不同,因此优化特定指令现在不会产生相同的效果。

对于 Javascript,现在变化非常迅速。它已经从被解释到被编译,这产生了巨大的性能差异。浏览器之间的编译器非常不同,并且随着每个新的浏览器版本而变化,所以今天在一个浏览器中更快的东西,明天可能会变慢。

我已经测试了一些优化循环的不同方法,目前性能差异很小:http: //jsperf.com/loopoptimisations

可以肯定的一件事是,编写循环的常规方式是最常见的,因此所有编译器都将专注于优化。

于 2012-09-03T12:12:14.490 回答