Firefox如何优化这个循环?

35

Firefox 9.0.1 在 n 很小时,使用 Ω(n) 的循环方法超越了我的 Ω(log n) 数字补零算法,这让我感到惊讶。在其他所有我见过的浏览器中,循环都比较慢,即使对于小值 n 也是如此。我知道所有的浏览器都在优化 JavaScript,但既然其他现代浏览器都显示循环更慢,那么是否有解释 Firefox 9 行为的原因呢?

// Ω(log n)
function padNumberMath(number, length) {
    var N = Math.pow(10, length);
    return number < N ? ("" + (N + number)).slice(1) : "" + number
}

// Ω(n):
function padNumberLoop(number, length) {
    var my_string = '' + number;
    while (my_string.length < length) {
        my_string = '0' + my_string;
    }
    return my_string;
}

更新:我不认为这与原问题有关,但我刚刚发现当从32位模式切换到64位模式时,IE 9会改变行为。在32位模式下,Math方法胜出,在64位模式下,Loop方法胜出。只是想指出这一点。

更新2:MAK在他下面的评论中纠正了我。数学方法不是Ω(1),可能更像是Ω(log n)。


5
哪个是Ω(1)方法?我不知道有比O(log n)更快的指数算法。 - MAK
你可能会假设,但你能否提供任何证据来“展示”循环展开正在发生? - David Wolever
@MAK 我忽略了指数运算的成本。已在编辑中修复。对于n≥1,log n < n,因此循环速度仍应该有一个解释。 - kojiro
1
“当 n 很小的时候,O(1)”听起来有点好笑 :) - Kos
@Kos 我不认为我曾经说过那句话。 ;) - kojiro
显示剩余2条评论
3个回答

11
测试结果就可以发现,Firefox并没有采取任何措施来提高性能。

browserscope

这些条形图可以看作是“速度”(操作/秒),因此更长的条形图意味着更好的性能。所有内容都按比例绘制。

在Firefox 9中,“Math”方法的性能表现极差,而“Loop”方法在各个版本之间变化很小。

因此,在Firefox 9中没有进行任何“优化”。 Firefox 8和9之间在这些测试方面发生的一切只是它们的数学库变慢了(Math.pow 变慢)或字符串库变慢了(.slice()变慢)。

进一步调查发现,在ff9中某种程度上这些基本操作变慢了

ff8 vs ff9

在FF 9中,连接和Math.pow都略微变慢了,这可能解释了您在测试中看到的差异。

有趣的是,在FF8中,新的no-op条比在FF9中长得多。


哇,看起来应该开一个 bug?我在 Firefox 9 上对我的一些代码进行了基准测试,它们声称的类型推断带来的 30% 的性能提升似乎是相当准确的...但我的代码并不涉及太多数学计算。 - ՕլՁՅԿ
1
第二个截图只是显示,如果进行一个没有副作用的无用的Math.pow调用,Firefox 8将消除死代码,而Firefox 9则不会。这与原始的减速没有太大关系,原始减速是由于Firefox 9中的Math.pow比Firefox 8慢大约40%,因为它没有被有效地调用。我建议编写基准测试时始终记住死代码消除优化。 - Boris Zbarsky
@BorisZbarsky 如果将函数的输出分配给一个名称,会抵消死代码检查吗? - kojiro
@BorisZbarsky 你说得对,所以我修改了测试,并添加了一个dead()部分(什么也不做),以确保测试不会无效(如果它们无效,它们将与dead()对齐)。然而,结果指向相同的结论,但在新测试中差异不是很大。 - bobobobo
@kojiro 打败死代码消除的唯一方法是确保该值最终存储在某个永久位置(例如全局变量)。将其分配给本地变量有时可能有效,但有时不行;这基本上取决于死代码消除器中的错误。 - Boris Zbarsky
@bobobobo 当然,实际上也会有约40%的减速。我已经说过了! - Boris Zbarsky

3

这可能就像将参数字符串复制到一个新的字符数组中那样快,该数组可能默认初始化为相关字符,在这种情况下是数字。

也许识别涉及常量的递归赋值可以快速将长度为mystring.length+1的“0”字符串与mystring连接起来。

或者这只是因为Firefox指数运算变得不那么精确,没有使用指数的二进制展开进行重复平方。


0
Firefox 9.0.1让我惊讶的是,当n很小时,它用一个Ω(n)的循环方法展示了我的Ω(1)数字填充算法。
这句话不是缺少一些部分吗?它应该显示为更快,或者其他什么吗?
还有,你为什么要将空字符串连接到数字上?为什么不直接构造一个字符串呢?
而且,你的O(1)实际上是O(log)...
无论如何,这个解释可能是由于Firefox 9中的类型推断

1
“Showing up” 可以表示 “做得比…更好”,例如 “我得了9分,但是Péter Varga得了11分,他比我做得更好”。不确定这是否是 OP 的意思,但这是我的理解。 - Wesley Murch
3
这里的“showing up”和“appearing”用法不同。他使用“show up”来表示“证明优于”。http://idioms.thefreedictionary.com/show+up - jela
@jela 确实,这就是我的意思。 - kojiro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接