Roy*_*son 3 javascript performance
当检查一个值是否x为布尔值时,是
typeof x === 'boolean'快于x === true || x === false或反之亦然?
我预计文字比较会更快,但似乎 typeof 比较几乎快两倍。
旁注:我知道这对于几乎任何实际目的来说都不重要。
这是基准代码(免责声明:我不知道如何进行基准测试): https: //jsperf.com/check-if-boolean-123
这取决于。
为了给出绝对的答案,我们必须在每种可能的浏览器/架构组合上编译每段代码/观察解释器。然后我们可以给出一个绝对的答案哪个操作需要更少的处理器周期,其他一切都纯粹是猜测。这就是我现在正在做的事情:
天真的方法
我们假设引擎不执行任何优化。他们只是执行规范中定义的每一步。然后对于每个测试用例都会发生以下情况:
typeof x === 'boolean'
x(1)查找的类型。由于引擎可能将通用“JavaScript 值”表示为具有指向实际数据的指针和值类型的枚举的结构,因此获取描述该类型的字符串可能是在类型 -> 类型字符串映射中查找。
(2) 现在我们有两个字符串值,我们必须对其进行比较 ( 'boolean' === 'boolean')。首先,必须检查类型是否相等。这可能是通过比较两个值的类型字段和按位相等(意思是:一个处理器操作)来完成的。
(3) 最后必须比较该值是否相等。对于字符串,这意味着迭代两个字符串并将字符相互比较。
x === true || x === false
(1) 首先,必须如上所述比较x和true和xad的类型。false
(2) 其次,必须比较这些值,对于布尔值来说,这是按位质量(意思是:一个处理器操作)。
(3) 最后一步是or表达式。给定两个值,首先必须检查它们的真实性(这对于布尔值来说非常容易,但我们仍然必须再次检查这些值是否真的是布尔值),然后可以进行或操作(按位或,意思是:一个处理器操作)。
那么哪一个更快呢?如果我不得不猜测,第二种方法,因为第一种方法必须执行字符串相等,这可能需要更多迭代。
最佳方法
一个非常聪明的编译器可能会意识到,typeof x === 'boolean'只有当 x 的类型是布尔值时,这才是正确的。所以它可以优化为(C++伪代码):
result = JSValue( JSType::Boolean, x->type == JSType::Boolean)
Run Code Online (Sandbox Code Playgroud)
这只是一些处理器操作,所以速度非常快。与简单的方法相比,我们节省了字符串比较和多次类型检查。引擎会做这样的优化吗?可能是因为typeof检查很常见,并且很容易优化(所以这是一个轻松的胜利)。
我们可以优化吗x === true || x === false?嗯,是的,我们知道 的类型true,false这可以归结为(C++ 伪代码):
var result = JSValue(JSType:Boolean, x->type == JSType:Boolean && !x->value || x->type == JSType:Boolean && x->value)
Run Code Online (Sandbox Code Playgroud)
就不能进一步优化吗?难道编译器看不出x->value和!x->value是互斥的,因此它实际上与上面的代码完全相同。编译器会做这种优化吗?我不知道。这绝对不是那么容易,而优化x || !x实际上是开发人员可以采取的一种简单的优化。
因此,在一个完美的世界中,如果有一个非常周到的编译器,第一个编译器会更快。
但编译器会优化那么多吗?这取决于。如今,引擎首先采用简单的方法(因为编译也花费时间),并且只有在函数变热(经常被调用)时才会进行优化。您的测试用例就是这种情况(这就是第二个测试用例更快的原因)。现实世界的代码是否变得热门实际上取决于用例。
带走
在我的设备上,第一个版本执行 451,701,256 次操作/秒(!!)。这么快吗?是的!
第二个版本的执行速度为 198,308,952 ops/s。是不是慢了一倍?是的。慢吗?不!可能还有其他代码片段会消耗更多的处理器周期。
进一步的想法
一个非常常见的优化是在推导参数的数据类型后编译函数。这意味着如果你这样做
const check = it => typeof it === "boolean";
for(let i = 0; i < 100000; i++) check(true); // make function hot
Run Code Online (Sandbox Code Playgroud)
该函数可能会被编译为
boolean check(/*deduced datatype*/ boolean it) {
return true; // <- even faster than anything above
}
Run Code Online (Sandbox Code Playgroud)
现在如果你打电话会发生什么check("ouch")?好吧,在函数的入口点,类型被断言,断言失败,引擎必须回退到解释/重新编译函数。因此,使用布尔值调用函数 100000 次,然后使用字符串调用函数 100000 次可能比随机使用字符串/布尔值调用函数 200000 次更快。编写性能测试时请记住这一点。
| 归档时间: |
|
| 查看次数: |
820 次 |
| 最近记录: |