未定义变量vs未定义属性混淆性能



我正在做一些基准测试,发现一些荒谬的结果,我似乎无法解释。

const a = undefined;
const b = {};
// add tests
suite
.add('Undefined variable', function () {
if(a > 0){
return true;
}
else{
return false;
}
})
.add('Undefined property', function () {
if(b.a > 0) {
return true;
}
else{
return false;
}
})

测试结果:

Undefined variable x 69,660,401 ops/sec ±2.48% (36 runs sampled)
Undefined property x 994,939,175 ops/sec ±0.85% (40 runs sampled)
Test Results
--------------------------------------------------------------------------
Undefined property        : 994939174.67 ops/sec (+1328.27 %)
Undefined variable        : 69660400.51 ops/sec (  +0.00 %)
--------------------------------------------------------------------------

有人知道为什么第一种情况Undefined variable比另一种慢得多吗?我在jsbench测试中发现了类似的性能结果:https://jsbench.me/vdku4ert4l/2

(这里是V8开发人员)

比较undefined > 0总是具有相同的性能。这里的差别是,在你的情况下,V8可以优化掉比较:像b.a属性访问,它记得隐藏类的对象(s)(即b的值);这就是"内联缓存"技术的关键思想。

V8将这个想法更进一步:如果所有遇到的对象都有相同的隐藏类,并且该隐藏类没有a属性,那么当该函数得到优化时,V8会考虑到这一经验并生成优化的代码,并假设将来仍然会出现这种情况,在这种情况下,它可以不断地减少属性加载和比较。换句话说,它将该函数优化为:

function undefined_property_optimized() {
(if b.__hidden_class__ !== kPreviousHiddenClass) Deoptimize;
return false;
}

其中Deoptimize的意思是:扔掉这个优化过的代码,回到这个函数的未优化代码(当然,在正确的点恢复执行)。

第一个测试Undefined variable被严重减慢

不,它不是被放缓。其他案件"cheating",所以说话。

添加const b = { a: undefined };不会改变任何东西

这实际上在很大程度上取决于你如何准确地运行测试。在本地测试,少量修改我力引擎,这要么没有影响,要么使两个函数相等的速度。

经验法则#1:当你运行一个微基准测试时,你看到每秒数亿次的操作,那么优化编译器能够优化掉几乎所有的东西,你正在测试一个空的(或微不足道的)函数。

经验法则#2:微基准测试的结果很难正确解释。您可能认为您在这里测量的是属性负载,或者> 0比较;这两个假设都是不正确的:在更快的情况下,没有加载属性,也没有执行> 0比较。为了理解微基准测试,你真的需要研究生成的机器代码(和/或其他引擎内部),以确保它在测试你认为它在测试的东西。

经验法则#3:现代高性能JavaScript引擎是非常复杂的野兽,同样的JS代码片段而不是总是具有相同的性能;它在很大程度上取决于它周围的代码(无论是直接周围的行,还是应用程序中其他地方的代码都可能影响它)。

经验法则#4:微基准测试的结果几乎不会影响到现实世界的代码——主要是因为上面的三条规则:-)


边注:当你发现自己在写:

if (some_condition) {
return true;
} else {
return false;
}

那么你可以用return some_condition替换它。可能不会更快,但使您的代码更短。

最新更新