zoukankan      html  css  js  c++  java
  • 缓存 Array.length 是老生常谈的小优化

    问题

    缓存 Array.length 是老生常谈的小优化。

    // 不缓存 
    for (var i = 0; i < arr.length; i++) {
    ...
    }
    
    // 缓存
    var len = arr.length;
    for (var i = 0; i < len; i++) {
    ...
    }
    
    // 或者
    for (var i = 0, len = arr.length; i < len; i++) {
    ...
    }

    但以前写过 Java 的笔者一直对这种破碎的写法感到不适,也对这种写法的实际优化效果产生疑问。

    且推崇这种写法的朋友似乎很多也是“前辈这么说+自己想了一下觉得有道理”。

    由于 for 循环搭配 Array.length 是极度常用的 JavasScript 代码,所以还是有必要搞清楚的。

    结论

    经过一番摸索后笔者得到的结论是:缓存 Array.lengh 对优化的影响没有想象中的大,甚至可能会有所减慢。

    理由

    从测试结果上看

    stackoverflow 上也有这个讨论,For-loop performance: storing array length in a variable 。

    accepted 的答案是说缓存会起到加速的结果,给出了 jsPerf 测试。

    但是有答案反对,也给出了 jsPerf 测试。

    两个答案的区别在于“循环不变量代码移动(Loop-invariant code motion)”,accepted 答案的测试循环里没有访问到数组,是不实际的,后面会讲到。

    从另一篇文章 Shoud I have to cache my array’s length? 的测试结果也可以看出缓存差别不大。

    1

    还有这篇 JavaScript's .length Property is a Stored Value

    2

    从 V8 的中间代码分析

    这篇文章 How the Grinch stole array.length access 从 V8 的 hydrogen 探讨 Array.length 在 for 循环中的处理。

    正如上面提到的“循环不变量代码移动”,V8 引擎会聪明的把能确定不变的代码移到循环外。

    所以像下面这种代码也不会影响引擎对 Array.length 的优化:

    function uncached(arr) {
      for (var i = 0; i < arr.length; i++) {
        arr[i]
      }
    }

    而当在循环中调用函数时,V8 会尝试将函数进行内联,从而继续进行“循环不变量代码移动”优化。
    但当函数不可内联时,V8 就没辙了,每次循环都要重新计算一遍 length

    function BLACKHOLE(sum, arr) {
      try { } catch (e) { }
    }
    
    function uncached(arr) {
      var sum = 0;
      for (var i = 0; i < arr.length; i++) {
        sum += arr[i];
        if (sum < 0) BLACKHOLE(arr, sum);
      }
      return sum;
    }

    但这时即便是在循环外缓存了 length 也是没有用的,引擎没法预判数组的变化,当需要访问数组元素时会触发 bounds check ,从而照样要计算一遍 length 。所以缓存 length 是没有用的。

    甚至,由于多了一个变量,底层的寄存器分配器每次循环还要多一次恢复这个变量。当然这个只有在大规模的情况下才会看出区别。

    结尾

    当然这篇文章也有局限性,仅仅讨论了 V8 引擎,也没有讨论访问 length 代价更高的 HTMLCollection 。但这已经足够说明两者差别不大,一般情况下我们不用再局限于缓存的写法,可以放开来按照自己喜欢的方式去写循环了。

    【完】

    原文:http://div.io/topic/966

  • 相关阅读:
    [leetcode] 135. Candy (hard)
    [leetcode] 134. Gas Station (medium)
    [OpenGL] 绘制并且判断凹凸多边形、自相交多边形。
    [leetcode] 45. Jump Game II(hard)
    [leetcode] 55. Jump Game (Medium)
    [leetcode] 392. Is Subsequence (Medium)
    [leetcode] 147. Insertion Sort List (Medium)
    [leetcode]914. X of a Kind in a Deck of Cards (easy)
    [leetcode] 234. Palindrome Linked List (easy)
    [leetcode] 290. Word Pattern (easy)
  • 原文地址:https://www.cnblogs.com/qiuzhimutou/p/5068041.html
Copyright © 2011-2022 走看看