****澄清**:我不是在寻找最快的代码或优化。我想了解为什么一些似乎没有优化或优化的代码实际上通常运行得更快。
短版
为什么是这个代码:
var index = (Math.floor(y / scale) * img.width + Math.floor(x / scale)) * 4;
比这个性能更好?
var index = Math.floor(ref_index) * 4;
长版
本周,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 ];
}
}
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;
}
}
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(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;
}
}
jsPerf:http: //jsperf.com/so-accessing-local-variable-doesn-t-improve-performance
最后两个的唯一区别是'index'变量的计算。令我惊讶的是,优化版本在大多数浏览器(除了歌剧)中都比较慢。
个人测试结果(不是 jsPerf 测试):
歌剧
Original: 8668ms Optimized: 932ms Hybrid: 8696ms
铬合金
Original: 139ms Optimized: 145ms Hybrid: 136ms
苹果浏览器
Original: 433ms Optimized: 853ms Hybrid: 451ms
火狐
Original: 343ms Optimized: 422ms Hybrid: 350ms
在挖掘之后,由于范围查找,似乎一个通常的好习惯是主要访问局部变量。因为优化后的版本只调用一个局部变量,所以除了涉及的各种操作之外,调用多个变量和对象的混合代码应该更快。
那么为什么“优化”版本更慢呢?
我认为这可能是因为某些 JavaScript 引擎没有优化优化版,因为它不够热,但是--trace-opt
在 chrome 中使用后,似乎所有版本都被 V8 正确编译。
在这一点上,我有点无能为力,想知道是否有人会知道发生了什么?
我还在这个页面中做了一些更多的测试用例: