简体   繁体   English

为什么 if(1) 比 if(true) 快

[英]Why is if(1) faster than if(true)

I'm trying to make Conway's game of life in JavaScript and canvas, I have a matrix of 1280x720 that I use to store cells data, I'm currently storing the data as 1 = alive, 0 = dead, and then when I check if a cell is alive or not I simply do: if(matrix[i][j]) I was curious if this could be improved and did some tests at https://jsbench.me/ replicating a similar scenario and noticed that if using "true/false", the whole thing is +-11% slower, why is it the case?我正在尝试在 JavaScript 和 canvas 中制作康威的生命游戏,我有一个 1280x720 的矩阵用于存储单元格数据,我目前将数据存储为 1 = 活着,0 = 死亡,然后当我检查如果一个细胞是活的,我只是做: if(matrix[i][j])我很好奇这是否可以改进,并在https://jsbench.me/进行了一些测试,复制了类似的场景并注意到如果使用“真/假”,整个事情慢了+-11%,为什么会这样? Shouldn't it be faster?不应该更快吗?

Example benchmark, just change 1 to true to test the other scenario示例基准,只需将 1 更改为 true 即可测试其他场景

let array = []
for(let i = 0; i<1000000; i++){
   array.push(1)
}
let sum = 0
for(let i = 0; i<1000000;i++){
    if(array[i]){
        sum++
    }
}

The performance difference you see isn't strictly due to the if statement evaluation, it's due to the array element kind that the value ( 1 or true ) is accessed from.您看到的性能差异并非严格归因于if语句评估,而是归因于访问值( 1true )的数组元素类型。 The V8 engine distinguishes between arrays of different element kinds . V8引擎区分不同元素种类的arrays An array of 1 will be treated as PACKED_SMI_ELEMENTS , while an array of true will be treated as PACKED_ELEMENTS . 1的数组将被视为PACKED_SMI_ELEMENTS ,而true的数组将被视为PACKED_ELEMENTS Because of that, the version using boolean elements will be a little bit slower.因此,使用 boolean 元素的版本会慢一些。

As an illustration, here's the lattice of relative performance optimizations applied between array element kinds, with best performance at the top left, and worst performance at the bottom right:作为说明,这是在数组元素类型之间应用的相对性能优化的网格,左上角的性能最佳,右下角的性能最差:

元素种类格

And here's a benchmark comparing both your tests to one I added based on my comment below :这是一个基准,将您的测试与我根据 以下评论添加的测试进行比较:

基准测试结果

(V8 developer here.) (这里是 V8 开发人员。)

In short, the 1/0 version is faster because the array's elements kind helps the if statement do less work.简而言之,1/0 版本更快,因为数组的元素种类有助于if语句做更少的工作。

Longer version: As @PatrickRoberts points out, V8 keeps track of the type of values stored in an array.更长的版本:正如@PatrickRoberts 指出的那样,V8 会跟踪存储在数组中的值的类型。 This mechanism is rather coarse-grained, it only distinguishes between "just integers", "just doubles", and "anything".这种机制是相当粗粒度的,它只区分“just integers”、“just doubles”和“anything”。 if(array[i]) , when it knows that the array contains only integers, can simply do a comparison against 0 to see if the branch should be taken. if(array[i]) ,当它知道数组只包含整数时,可以简单地与 0 进行比较以查看是否应采用分支。 It doesn't get faster than that.它不会比这更快。 If the array contains "anything" (which includes true ), however, then per the semantics of JavaScript, V8 has to check whether the loaded value is "true-ish", ie evaluates to true in a conditional context.但是,如果数组包含“任何内容”(包括true ),那么根据 JavaScript 的语义,V8 必须检查加载的值是否为“true-ish”,即在条件上下文中评估为 true。 The opposite, ie checking for false-ish values, is actually easier/faster, so V8 checks: is the value false ?相反,即检查假值,实际上更容易/更快,因此 V8 检查:值是否为false Is it "" ?""吗? Is it a number (which might be 0)?它是一个数字(可能是 0)吗? Is it a BigInt (which might be 0n)?它是 BigInt(可能是 0n)吗? Is it document.all (a particularly fun special-case relic from ancient times)?是不是document.all (一个特别好玩的古代特例遗物)? Anything else evaluates to true .其他任何东西的计算结果true In this particular case , it would be "smart"/lucky to check for true right away, but the engine can't know that, and such a heuristic wouldn't be beneficial in general.在这种特殊情况下,立即检查是否为true “聪明的”/幸运的,但引擎无法知道这一点,而且这种启发式一般不会有好处。

(Note that it would be wrong to conclude that if(1) is faster than if(true) -- what matters specifically is that the value in the conditional is loaded from an array, and this array keeps track of the range of possible values, which affects the checks that subsequently need or don't need to be done on a loaded value. When you use constants 1 and true , then both evaluations have the same speed (in fact, in most situations the optimizing compiler will drop them entirely, because of course if(true) is true, duh.).) (请注意,得出if(1)if(true)快的结论是错误的——特别重要的是条件中的值是从数组中加载的,并且该数组会跟踪可能值的范围, 这会影响随后需要或不需要对加载的值进行的检查。当您使用常量1true时,两个评估具有相同的速度(实际上,在大多数情况下,优化编译器将完全放弃它们,因为当然if(true)是真的,duh.)。)

That said, most of the difference you see isn't due to this, because the test spends more than 90% of its time in the first loop, populating the array.也就是说,您看到的大部分差异都不是因为这个,因为测试在第一个循环中花费了超过 90% 的时间来填充数组。 Growing an array from length 0 to a million means its backing store needs to be extended repeatedly, which means a new backing store is allocated and all existing elements are copied over.将一个数组从长度 0 增加到一百万意味着它的后备存储需要重复扩展,这意味着分配一个新的后备存储并复制所有现有元素。 This is another operation where integer-only elements have a speed benefit: they can use a bulk copying operation, moving data as fast as the CPU can access memory.这是另一个仅整数元素具有速度优势的操作:它们可以使用批量复制操作,移动数据的速度与 CPU 访问 memory 的速度一样快。 In an "anything" array, however, the garbage collector must perform an additional pass to see if any of the values are references that are of interest to it.然而,在“anything”数组中,垃圾收集器必须执行额外的传递以查看是否有任何值是它感兴趣的引用。 In this case, with all values being the true sentinel, they're not, but the GC can't know that without checking.在这种情况下,所有值都是true的哨兵,但它们不是,但 GC 在不检查的情况下无法知道这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM