访问本地变量不会提高性能

Nic*_*ier 11 javascript optimization

****澄清**:我不是在寻找最快的代码或优化.我想了解为什么一些似乎没有经过优化或优化的代码实际上总体上更快地运行.

简短的版本

为什么这段代码:

var index = (Math.floor(y / scale) * img.width + Math.floor(x / scale)) * 4;
Run Code Online (Sandbox Code Playgroud)

比这个更高效?

var index = Math.floor(ref_index) * 4;
Run Code Online (Sandbox Code Playgroud)

长版

本周,Impact js的作者发表了一篇关于一些渲染问题的文章:

http://www.phoboslab.org/log/2012/09/drawing-pixels-is-hard

在文章中,有一个函数的来源,通过访问画布中的像素来缩放图像.我想建议一些传统方法来优化这种代码,以便在加载时缩短.但经过测试后,我的结果大部分时间都是最初的功能.

猜测这是JavaScript引擎正在进行一些智能优化,我试图了解更多内容,所以我做了一堆测试.但是我的结果很混乱,我需要一些帮助来了解发生了什么.

我这里有一个测试页面:

http://www.mx981.com/stuff/resize_bench/test.html

jsPerf:http://jsperf.com/local-variable-due-to-the-scope-lookup

要开始测试,请单击图片,结果将显示在控制台中.

有三种不同的版本:

原始代码:

for( var y = 0; y < heightScaled; y++ ) {
    for( var x = 0; x < widthScaled; x++ ) {
        var index = (Math.floor(y / scale) * img.width + Math.floor(x / scale)) * 4;
        var indexScaled = (y * widthScaled + x) * 4;
        scaledPixels.data[ indexScaled ] = origPixels.data[ index ];
        scaledPixels.data[ indexScaled+1 ] = origPixels.data[ index+1 ];
        scaledPixels.data[ indexScaled+2 ] = origPixels.data[ index+2 ];
        scaledPixels.data[ indexScaled+3 ] = origPixels.data[ index+3 ];
    }
}
Run Code Online (Sandbox Code Playgroud)

jsPerf:http://jsperf.com/so-accessing-local-variable-doesn-t-improve-performance

我试图优化它之一:

var ref_index = 0;
var ref_indexScaled = 0
var ref_step = 1 / scale;
for( var y = 0; y < heightScaled; y++ ) {
    for( var x = 0; x < widthScaled; x++ ) {
        var index = Math.floor(ref_index) * 4;
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index ];
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index+1 ];
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index+2 ];
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index+3 ];

        ref_index+= ref_step;
    }
}
Run Code Online (Sandbox Code Playgroud)

jsPerf:http://jsperf.com/so-accessing-local-variable-doesn-t-improve-performance

相同的优化代码,但每次都重新计算索引变量(Hybrid)

var ref_index = 0;
var ref_indexScaled = 0
var ref_step = 1 / scale;
for( var y = 0; y < heightScaled; y++ ) {
    for( var x = 0; x < widthScaled; x++ ) {
        var index = (Math.floor(y / scale) * img.width + Math.floor(x / scale)) * 4;
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index ];
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index+1 ];
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index+2 ];
        scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ index+3 ];

        ref_index+= ref_step;
    }
}
Run Code Online (Sandbox Code Playgroud)

jsPerf:http://jsperf.com/so-accessing-local-variable-doesn-t-improve-performance

最后一个的唯一区别是'index'变量的计算.令我惊讶的是,优化版本在大多数浏览器中都比较慢(除了opera).

个人测试的结果(不是jsPerf测试):

在挖掘之后,通常的好习惯是由于范围查找而主要访问局部变量.因为优化版本只调用一个局部变量,所以除了涉及的各种操作之外,调用多个变量和对象的混合代码应该更快.

那么为什么"优化"版本更慢?

我认为这可能是因为某些JavaScript引擎没有优化优化版本,因为它不够热,但在使用--trace-optchrome之后,似乎所有版本都由V8正确编译.

在这一点上,我有点无能为力,想知道是否有人会知道发生了什么?

我在这个页面中还做了一些测试用例:

http://www.mx981.com/stuff/resize_bench/index.html

小智 1

尽管听起来很愚蠢,但Math.whatever()对于 JS 引擎来说,这些调用的优化和内联可能会很棘手。只要有可能,最好使用算术运算(而不是函数调用)来获得相同的结果。

将以下第四个测试添加到http://www.mx981.com/stuff/resize_bench/test.html

// Test 4
console.log('- p01 -');
start = new Date().getTime();
for (i=0; i<nbloop; i++) {
  var index = 0;
  var ref_indexScaled = 0
  var ref_step=1/scale;


  for( var y = 0; y < heightScaled; y++ ) {
    for( var x = 0; x < widthScaled; x++ ) {
      var z= index<<2;
      scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ z++ ];
      scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ z++ ];
      scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ z++ ];
      scaledPixels.data[ ref_indexScaled++ ] = origPixels.data[ z++ ];

      index+= ref_step;
    }
  }
}
end = new Date().getTime();
console.log((end-start)+'ms');
Run Code Online (Sandbox Code Playgroud)

在 Opera Next 中产生以下数字:

  • 原始 - 2311ms
  • 重构 - 112ms
  • 混合 - 2371ms
  • p01 - 112ms