对于VS Foreach on Array性能(在AS3 / Flex中)

时间:2009-06-18 05:06:27

标签: performance flash actionscript-3 flex actionscript

哪一个更快?为什么呢?

var messages:Array = [.....]

// 1 - for
var len:int = messages.length;
for (var i:int = 0; i < len; i++) {
    var o:Object = messages[i];
    // ...
}

// 2 - foreach
for each (var o:Object in messages) {
    // ...
}

8 个答案:

答案 0 :(得分:23)

从我所在的位置开始,在最小的情况下,常规for循环比for each循环要快一些。此外,与AS2日一样,通过for循环递减通常会提供非常小的改进。

但实际上,这里的任何细微差别都会与您在循环中实际执行的操作的要求相比相形见绌。在任何一种情况下,您都可以找到更快或更慢的操作。真正的答案是,任何一种循环都不能有意义地说比另一种循环更快 - 你必须在应用程序中显示你的代码。

示例代码:

var size:Number = 10000000;
var arr:Array = [];
for (var i:int=0; i<size; i++) { arr[i] = i; }
var time:Number, o:Object;

// for()
time = getTimer();
for (i=0; i<size; i++) { arr[i]; }
trace("for test: "+(getTimer()-time)+"ms");

// for() reversed
time = getTimer();
for (i=size-1; i>=0; i--) { arr[i]; }
trace("for reversed test: "+(getTimer()-time)+"ms");

// for..in
time = getTimer();
for each(o in arr) { o; }
trace("for each test: "+(getTimer()-time)+"ms");

结果:

for test: 124ms
for reversed test: 110ms
for each test: 261ms

编辑:为了改进比较,我更改了内部循环,因此除了访问集合值之外什么都不做。

编辑2:oshyshko评论的答案:

  1. 编译器可以跳过内部循环中的访问,但事实并非如此。如果是循环,循环将退出两到三倍。
  2. 您发布的示例代码中的结果会发生变化,因为在该版本中,for循环现在具有隐式类型转换。为了避免这种情况,我从循环中离开了作业。 当然有人可能认为在for循环中有额外的演员阵容是可以的,因为“真正的代码”无论如何都需要它,但对我而言,这只是另一种说法“没有一般答案;哪个循环更快”取决于你在循环中做了什么“。这是我给你的答案。 ;)

答案 1 :(得分:2)

当迭代数组时,对于每个循环在我的测试中都会更快。

var len:int = 1000000;
var i:int = 0;
var arr:Array = [];

while(i < len) {
    arr[i] = i;
    i++;
}

function forEachLoop():void {
    var t:Number = getTimer();
    var sum:Number = 0;
    for each(var num:Number in arr) {
        sum += num;
    }
    trace("forEachLoop :", (getTimer() - t));
}

function whileLoop():void {
    var t:Number = getTimer();
    var sum:Number = 0;
    var i:int = 0;
    while(i < len) {
        sum += arr[i] as Number;                
        i++;
    }
    trace("whileLoop :", (getTimer() - t));
}

forEachLoop();
whileLoop();

这给出了:

forEachLoop:87 whileLoop:967

在这里,可能大部分while循环时间用于将数组项转换为Number。但是,我认为这是一个公平的比较,因为这就是你在每个循环中得到的结果。

我的猜测是,这种差异与如下事实有关:如上所述,as运算符相对昂贵且数组访问也相对较慢。对于每个循环,我认为这两个操作都是本机处理的,因为它们是在Actionscript中执行的。

但是,请注意,如果实际发生类型转换,则每个版本的速度要慢得多,而版本的版本如果速度要快得多(但是,对于每个版本来说仍然如此):

要测试,请将数组初始化更改为:

while(i < len) {
    arr[i] = i + "";
    i++;
}

现在的结果是:

forEachLoop:328 whileLoop:366

forEachLoop:324 whileLoop:369

答案 2 :(得分:2)

之前我与一些同事讨论过这个问题,我们都发现了不同场景的不同结果。然而,为了比较,我发现有一个测试非常雄辩:

var array:Array=new Array();
for (var k:uint=0; k<1000000; k++) {
    array.push(Math.random());
}

stage.addEventListener("mouseDown",foreachloop);
stage.addEventListener("mouseUp",forloop);

/////// Array /////

/* 49ms */
function foreachloop(e) {
    var t1:uint=getTimer();
    var tmp:Number=0;
    var i:uint=0;
    for each (var n:Number in array) {
        i++;
        tmp+=n;
    }
    trace("foreach", i, tmp, getTimer() - t1);
}
/***** 81ms  ****/
function forloop(e) {
    var t1:uint=getTimer();
    var tmp:Number=0;
    var l:uint=array.length;
    for(var i:uint = 0; i < l; i++)
        tmp += Number(array[i]);
    trace("for", i, tmp, getTimer() - t1);
}

我喜欢这个测试的是你在两个循环的每次迭代中都有关键和值的引用(删除“for-each”循环中的密钥计数器并不相关)。此外,它使用Number运行,这可能是您想要优化那么多的最常见的循环。最重要的是,获胜者是“for-each”,这是我最喜欢的循环:P

注意:

- 在“for-each”循环函数中的局部变量中引用数组是无关紧要的,但在“for”循环中你会得到一个减速带(75ms而不是105ms):

function forloop(e) {
    var t1:uint=getTimer();
    var tmp:Number=0;
    var a:Array=array;
    var l:uint=a.length;
    for(var i:uint = 0; i < l; i++)
        tmp += Number(a[i]);
    trace("for", i, tmp, getTimer() - t1);
}

- 如果你使用Vector类运行相同的测试,结果有点令人困惑:S

答案 3 :(得分:1)

对于数组来说会更快......但是根据情况,它可能是最好的预测...请参阅此.net benchmark test

就个人而言,我会使用其中任何一个,直到我有必要优化代码。过早优化是浪费: - )

答案 4 :(得分:0)

也许在所有元素都存在的数组中,从零开始(0到X),使用for循环会更快。在所有其他情况下(稀疏数组),每个都可以更快地使用它。 原因是在数组中使用了两个数据结构:Hast表和Debse数组。 请使用Tamarin源阅读我的Array分析: http://jpauclair.wordpress.com/2009/12/02/tamarin-part-i-as3-array/

for循环将检查未定义的索引,其中每个将跳过那些跳转到HastTable中的下一个元素

答案 5 :(得分:0)

家伙! 尤其是 Juan Pablo Califano 。 我检查了你的测试。获取数组项的主要区别。 如果你放var len : int = 40000;,你会看到'while'周期更快。 但它失去了大量的数组,而不是......每个。

答案 6 :(得分:-1)

只是一个附加组件:

循环中每个...的 并不能保证 array / vector <中的元素< / strong>在它们中存储的订单中列举。 (XML除外) 这是一个重要的区别,IMO。

“...因此,你不应该编写依赖于 - 的代码 除非您正在处理,否则每个in或for-in循环的枚举顺序 XML数据......“C.Moock

(我希望不要违反法律陈述这一句话......)

快乐的基准测试。

答案 7 :(得分:-4)

很抱歉,证明你们错了,但每个人都更快。甚至很多。除非,如果你不想访问数组值,但a)这没有意义,b)这不是这里的情况。

因此,我在我的超级新博客上做了详细的post ......:D

格尔茨

back2dos