代码之家  ›  专栏  ›  技术社区  ›  Simon Schick

数组大小调整性能,设置长度属性与重复推送

  •  0
  • Simon Schick  · 技术社区  · 7 年前

    因此,我对以下代码进行了基准测试,试图找出哪种代码更具性能:

    'use strict';
    
    function addSetToArrayA(array, set) {
      for (const v of set) {
        array.push(v);
      }
    }
    function addSetToArrayB(array, set) {
      const origLength = array.length;
      const newLength = array.length + set.size;
      array.length = newLength;
      array[newLength - 1] = 0;
      let i = origLength;
      for (const v of set) {
        array[i++] = v;
      }
    }
    
    const set = new Set([1, 2, 3, 4, 5, 6]);
    
    console.time('addSetToArrayA');
    for (let i = 0;i<0xffffff;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      addSetToArrayA(base, set);
    }
    console.timeEnd('addSetToArrayA');
    
    console.time('addSetToArrayB');
    for (let i = 0;i<0xffffff;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      addSetToArrayB(base, set);
    }
    console.timeEnd('addSetToArrayB');
    

    结果让我有点吃惊:

    addSetToArrayA: 728.773ms
    addSetToArrayB: 3296.437ms
    

    'use strict';
    
    const iters = 0xfffff;
    
    console.time('32 push');
    for (let i = 0;i<iters;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      for (let k = 0;k<32;++k) {
        base.push(undefined);
      }
    }
    console.timeEnd('32 push');
    
    console.time('32 length');
    for (let i = 0;i<iters;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      base.length = 32;
    }
    console.timeEnd('32 length');
    
    console.time('64 push');
    for (let i = 0;i<iters;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      for (let k = 0;k<64;++k) {
        base.push(undefined);
      }
    }
    console.timeEnd('64 push');
    
    console.time('64 length');
    for (let i = 0;i<iters;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      base.length = 64;
    }
    console.timeEnd('64 length');
    
    console.time('128 push');
    for (let i = 0;i<iters;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      for (let k = 0;k<128;++k) {
        base.push(undefined);
      }
    }
    console.timeEnd('128 push');
    
    console.time('128 length');
    for (let i = 0;i<iters;++i) {
      const base = [1, 2, 3, 4, 5, 6];
      base.length = 128;
    }
    console.timeEnd('128 length');
    

    结果与我之前的经历一致:

    32 push: 132.061ms
    32 length: 180.745ms
    64 push: 284.575ms
    64 length: 212.465ms
    128 push: 586.747ms
    128 length: 268.689ms
    

    .length .push() ,而对于较大的阵列则更快(如预期的那样)。

    V8在使用时是否执行不同类型的数组大小调整 .length = ... 与。 .push(...) ? 这与V8如何处理稀疏数组有关吗?

    2 回复  |  直到 7 年前
        1
  •  6
  •   jmrk    7 年前

    .push() 超级优化,而 .length .push() 对于一些元素)。

    事实上,你会注意到,在 .长度 缩短数组并调用 .pop() 几次。

    我个人认为这不是一个糟糕的状态:你的 .push 基于脚本的代码简洁、直观、可读。这个 基于web的替代方案看起来像是试图挤出一点额外的性能,代价是让代码更难看、更复杂——这样做不是很好吗 救命啊?写你想写的代码,让引擎担心速度会变快!:-)

    V8在使用.length=…时正在执行不同类型的数组大小调整。。。与…推(…)?

    .长度 .push(...)

    这与V8如何处理稀疏数组有关吗?

    不是你的例子。一般来说,写信给 必须检查数组是否应该转换到稀疏模式,但检查本身相当快。