解释非零检查的性能测试



我最近又掉进了过早优化的陷阱,希望能爬出来。然而,在我短暂的休息中,我遇到了一些事情,我想确认一下。

我非常基本的性能测试在chrome上产生了类似的结果(所有变量只是全局声明,第一个需要~9ms,第二个~7.5ms):

input = Array.from({ length: 1000000 }, () => Math.random() > 0.8 ? 0 : Math.random() * 1000000000 );
start = performance.now();
for (let i = 0; i < 1000000; i++) {
input[i] = input[i] === 0 ? 0 : 1;
}
console.log(performance.now() - start);

input = Array.from({ length: 1000000 }, () => Math.random() > 0.8 ? 0 : Math.random() * 1000000000 );
start = performance.now();
for (let i = 0; i < 1000000; i++) {
input[i] = ((input[i] | (~input[i] + 1)) >>> 31) & 1;
}
console.log(performance.now() - start);

考虑到循环和赋值本身已经花费了很多时间(~4.5ms),第二个可能花费的时间要少33%,这比我期望的要小得多(并且在测量不准确的情况下,例如在FireFox上,两者都需要更长的时间,第二个要差33%)。

在这一点上,我是否可以得出结论,条件的优化已经发生,并且已经完成了类似的代码更改,或者我是否陷入了一些微基准的海市蜃楼?在我看来,这一类别的分支应该比计算耗费更多的时间。

我主要对自己的推理持怀疑态度,因为我知道,这类测试很容易因为不可预见的原因而产生偏差。

是的,这很可能是度量和jit编译器效果结合的结果。

特别是JS现代浏览器中启发式驱动的jit编译器是如此之好,以至于你将没有任何机会可视化"真实的"。直观上更快的语句带来的性能优势。

我的浏览器的差异是如此之高,两个代码需要大约相等的时间(在Opera中运行),这强调了你在FF中的效果。

很高兴你发现1.5毫秒的优势,你不会看到更多。

最新更新