Для VS Foreach по производительности массива (в AS3 / Flex)

Какой из них быстрее? Зачем?

<code>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) {
    // ...
}
</code>
 aJ.18 июн. 2009 г., 07:12
Вы можете легко оценить, используя какие-то таймеры?
 fenomas21 июн. 2009 г., 05:31
И ошышко: для каждого не просто синтаксический сахар, он устанавливает итератор в коллекционное значение, а не в индекс. Тем не менее, я думаю, что любое преимущество в скорости между типами циклов в реальном коде, вероятно, будет уменьшено такими вещами, как внутренние проверки типов или преобразования типов, которые трудно предсказать. Подходят ли результаты для общего случая к вашему реальному коду, я подозреваю, кто-то догадывается.
 fenomas21 июн. 2009 г., 04:11
Я думаю, что вы приняли ответ слишком рано. Я нашел противоположные результаты как back2dos.
 oshyshko18 июн. 2009 г., 08:33
Ну, да. Но мне любопытно узнать, как эти вещи реализованы во флеш-плеере. Может быть, некоторые из них производят больше мусора (например, объекты итератора), или они эквивалентны - и & quot; foreach & quot; это просто синтетический сахар для "для"?

Ответы на вопрос(8)

и мы все нашли разные результаты для разных сценариев. Однако был один тест, который я нашел довольно красноречивым для сравнения:

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);
}

Что мне нравится в этих тестах, так это то, что у вас есть ссылка как на ключ, так и на значение в каждой итерации обоих циклов (удаление счетчика ключей в цикле «для каждого» не имеет значения). Кроме того, он работает с Number, который, вероятно, является наиболее распространенным циклом, который вы хотите оптимизировать. И самое главное, победителем является «для каждого», который является моим любимым циклом: P

Заметки:

- Ссылка на массив в локальной переменной в функции «для каждого»; Цикл не имеет значения, но в "for" Цикл, вы получаете ускорение (75 мс вместо 105 мс):

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

 24 июн. 2009 г., 20:43
Как и в случае с ответом Хуана, стоит отметить, что если вы удалите приведение Number () и суммируете значения отрицательно (с - = вместо + =), цикл for выходит быстрее. Конечно, я понимаю причину, по которой стоит включить приведение числа (), поскольку вы получаете его бесплатно с помощью for..each, но опять же, я не могу вспомнить случай, когда код работал бы с приведением типа иначе, чем без него. ...

что вы, ребята, ошибаетесь, но для каждого это быстрее. даже много. за исключением случаев, когда вы не хотите получать доступ к значениям массива, но а) это не имеет смысла и б) здесь это не так.

В результате я сделал подробныйсообщение в моем супер новом блоге ...: D

Greetz

back2dos

 22 июн. 2009 г., 11:56
Теперь я знаю, чей блог НЕ читать ...
 24 июн. 2009 г., 17:48
+ 1. Я думаю, что вы правы в этом, хотя некоторые люди, похоже, не согласны (хотя, не читайте ваш блог).
 21 июн. 2009 г., 04:09
Я не покупаю эти результаты. Вы выполняете назначение переменных в своих циклах for по сравнению с увеличением для каждого из них. Чтобы сравнить циклы, вы должны также выполнить присваивание в каждом цикле, и если вы сделаете это, результаты обратные. (Между прочим, урок заключается в том, что разница в производительности между стилями цикла мала по сравнению с назначением одной переменной и, таким образом, довольно тривиальна.)
 19 июн. 2009 г., 01:49
доказать, кто не прав? Этот сайт не предназначен для того, чтобы доказывать, что люди неправы, а для того, чтобы давать людям правильные ответы, за которые проголосовали ваши коллеги. Если мой ответ не поможет, тогда за него не проголосуют. У меня нет проблем с этим. Что касается вашего ответа, то было бы неплохо, если бы вы предоставили больше доказательств, чем собственный пост в блоге ... в противном случае он кажется таким же надежным, как редактирование статей в Википедии в вашу пользу ;-)

ОсобенноJuan Pablo Califano. I've checked your test. The main difference in obtain array item. If you will put var len : int = 40000;, вы увидите, что «пока» цикл быстрее. Но он проигрывает с большим количеством массивов, а не для ... каждого.

for each...in Цикл не гарантирует, что элементы вarray/vector перечисляется в ПОРЯДКЕ, ОНИ ХРАНЕНЫ в них. (кроме XML) Это существенная разница, ИМО.

& quot; ... Поэтому не следует писать код, который зависит от порядок перечисления в каждом цикле или в цикле, если вы не обрабатываете Данные XML ... & quot; C.Moock

(Я надеюсь не нарушать закон, утверждая эту фразу ...)

Счастливый бенчмаркинг.

 14 февр. 2011 г., 02:15
Есть ли шанс привести пример, когда цикл не работает в том порядке, который вы ожидаете?
Решение Вопроса

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: Ответы на комментарий ошышко:

The compiler could skip the accesses in my internal loops, but it doesn't. The loops would exit two or three times faster if it was. The results change in the sample code you posted because in that version, the for loop now has an implicit type conversion. I left assignments out of my loops to avoid that. Of course one could argue that it's okay to have an extra cast in the for loop because "real code" would need it anyway, but to me that's just another way of saying "there's no general answer; which loop is faster depends on what you do inside your loop". Which is the answer I'm giving you. ;)
 22 июн. 2009 г., 11:53
Почему это получило отрицательный голос?
 24 июн. 2009 г., 19:50
Хуан: Я не удалил доступ к предмету; все циклы в моем примере содержат один доступ. Я удалил присвоение переменной, которое может быть необходимо в одних циклах и ненужным в других.
 22 июн. 2009 г., 05:43
ошышко, смотри мою правку. Почему декремент быстрее, я предполагаю, что это потому, что + имеет внутреннюю проверку типа, поскольку он может применяться как к строкам, так и к числам, а ++ наследует это. Но учитывая, что это добавляет всего несколько мс за 10 миллионов итераций, я, вероятно, даже не упомянул об этом. Это то, что людям, вероятно, лучше не знать. ;)
 24 июн. 2009 г., 17:35
Феномас. Я думаю, что, удалив доступ к элементу, вы упустите весь смысл. С foreach вам не нужно выполнять назначение в Actionscript (что медленнее), но вы можете получить доступ к каждому элементу в массиве (и в типизированном виде). С циклом for вы должны сделать это вручную. ОП спрашивал о производительности цикла в массивах, и я думаю, что если вы зацикливаете массив, вы делаете это для доступа к содержащимся в нем элементам. Итак, я определенно думаю, что задание в цикле for должно быть там.
 oshyshko21 июн. 2009 г., 21:35
@fenomas arr [i] может быть пропущен интерпретатором, поскольку результат игнорируется. Также сделайте тип значения строгим: & quot; o: Object & quot; - & GT; & Quot; O: Число & Quot ;. Попробуйте это: 1) var time: Number, o: Number, v: Number 2) replace & quot; arr [i] & quot; - & GT; & quot; v = arr [i] & quot; 3) // for..in time = getTimer (); для каждого (o в обр) {v = o; } трассировка ("для каждого теста:" + (getTimer () - время) + "мс"); Мои результаты с Игроком 10: [трассировка] для теста: 895мс [трассировка] для обратного теста: 565мс [трассировка] для каждого теста: 750мс КСТАТИ: как вы думаете, почему реверс лучше? Это потому, что "я & gt; = 0" может быть быстрее, чем «размер»?

каждый цикл проходит намного быстрее в моих тестах.

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

Здесь, вероятно, большая часть времени цикла тратится на приведение элемента массива к числу. Однако я считаю это справедливым сравнением, поскольку именно это вы получаете в каждом цикле.

Я предполагаю, что это различие связано с тем, что, как уже упоминалось, оператор as является относительно дорогим, а доступ к массиву также относительно медленным. Я думаю, что для каждого цикла обе операции обрабатываются изначально, в отличие от выполняемых в Actionscript.

Тем не менее, обратите внимание, что если преобразование типов действительно имеет место, то для каждой версии намного медленнее, а версия while заметно быстрее (хотя, тем не менее, для каждой доли while):

Чтобы проверить, измените инициализацию массива на это:

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

И теперь результаты:

forEachLoop: 328 whileLoop: 366

forEachLoop: 324 whileLoop: 369

 21 июн. 2009 г., 09:24
Что касается циклов while / for, то около года назад я разместил разорванный байт-код обоих циклов во флэш-кодерах & apos; Список показывает, что почти нет разницы. (Я могу перепостить их, если вы пожелаете). Что еще более важно, тесты не показали существенной разницы. Поэтому я сомневаюсь, что использование цикла for вместо цикла while будет иметь какое-то значение. В любом случае, я изменил код для использования цикла for и даже избавился от & quot; as & quot; оператор. Тем не менее, для каждой версии требуется 57 мс против 679 мс цикла for. Я согласен, что большую часть времени проводит в теле цикла. Тем не менее, при прочих равных условиях, каждый работает быстрее.
 24 июн. 2009 г., 20:04
Хуан, я согласен, что бывают случаи, когда каждый быстрее. Есть также случаи, когда это не так. То, что я говорю, это две вещи: во-первых, в самых минимальных случаях цикл for выполняется быстрее, поэтому, если можно сказать, что любой вид сортировки является «внутренним»; быстрее, это цикл for. Во-вторых, в неминимальных случаях, какой цикл быстрее, зависит от тела цикла. Следовательно, нет общего варианта ответа.
 21 июн. 2009 г., 06:57
Э-э, этот код не сравнивает, какой цикл быстрее; производительность того, что делается внутри каждого цикла, явно уменьшает разницу между стилями самих циклов. Конечно, урок того, что цикл быстрее, зависит от того, что вы в нем делаете. Кроме того, измените цикл while () на цикл for (), и он значительно ускорится. Не знаю почему, предположительно, внутренняя оптимизация.
 24 июн. 2009 г., 20:25
Ах, две другие заметки. Во-первых, я определенно забираю то, что я сказал, потому что () быстрее, чем while (), это была моя ошибка. Во-вторых, если вы все еще думаете, что ваш пример кода является хорошим общим случаем, попробуйте удалить & quot; as & quot; оператор, а затем измените & quot; + = & quot; операторы в ваших циклах для & quot; - = & quot; операторы. Цикл while теперь будет значительно быстрее, что означает, что в ваших результатах преобладает внутренняя проверка типа оператора +, а не природа самих циклов.
 24 июн. 2009 г., 22:21
Ну, может быть. Не проверял с помощью - = (я проверял удаление "как"). В любом случае, я согласен, что в некоторых случаях цикл for может быть быстрее, как показывают ваши образцы. Что еще более важно, как я думаю, мы оба согласились, узкое место в большинстве "реальных" петли будут его телом, а не механизмом петли; и в большинстве реальных случаев вы не повторяете более 10000000 элементов. Я имел тенденцию использовать циклы while (или for) почти исключительно, но когда я понял, что каждый из них не был значительно медленнее в большинстве случаев, которые я тестировал (и был быстрее во многих из них), а также более читабельным и кратким (по крайней мере для меня) Я переключился на каждого.

в массиве, где все элементы находятся там и начинаются с нуля (от 0 до X), было бы быстрее использовать цикл for. Во всех других случаях (разреженный массив) это может быть ОЧЕНЬ быстрее, чтобы использовать для каждого. Причина заключается в использовании двух структур данных в массиве: таблица Hast и массив Debse. Пожалуйста, прочитайте мой анализ массива с использованием источника Тамарин: http://jpauclair.wordpress.com/2009/12/02/tamarin-part-i-as3-array/

Цикл for будет проверять с неопределенным индексом, где для каждого будет пропускаться переход к следующему элементу в HastTable

использовать foreach ... посмотрите этоТест производительности .net.

Лично я использую их до тех пор, пока не доберусь до того момента, когда мне станет необходимо оптимизировать код. Преждевременная оптимизация расточительна :-)

 18 июн. 2009 г., 22:00
for each быстрее в AS3, чемfor - дайте ему оценку, если хотите.
 18 июн. 2009 г., 08:39
Но совет все еще правильный.
 18 июн. 2009 г., 09:18
@Unreality Да, когда я опубликовал свой ответ, я знал, что он запрашивает as3, а не .net, но я чувствовал, что контрольный тест (для которого я не смог найти тест для as3 конкретно) достаточно показателен для общей эффективности любой цикл for / foreach.
 18 июн. 2009 г., 08:41
Тем не менее, он все еще прав, в AS3, поскольку циклы немного быстрее, чем для каждого цикла. Это потому, что циклы являются прямой ссылкой.
 18 июн. 2009 г., 08:28
он спрашивает as3, а не .net framework. Разные языки выполняют коды по-разному

Ваш ответ на вопрос