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

var stuff = from l in File.ReadAllLines(filename)
            let x = l.Split(new [] {',', ' '}, StringSplitOptions.RemoveEmptyEntries)
                     .Skip(1)
                     .Select(s => int.Parse(s))
            select new
            {
                Sum = x.Sum(),
                Average = x.Average()
            };

Если вы читаете большие файлы и использование памяти вызывает беспокойство, то с помощью .NET 4 будет лучше работать следующее:

var stuff = from l in File.ReadLines(filename)
            let x = l.Split(new [] {',', ' '}, StringSplitOptions.RemoveEmptyEntries)
                     .Skip(1)
                     .Select(s => int.Parse(s))
            select new
            {
                Sum = x.Sum(),
                Average = x.Average()
            };

В обоих случаях переменная stuff содержит перечислимое, которое фактически не будет выполнено, пока вы не начнете читать из него (например, внутри цикла foreach).

16
задан Benny 29 October 2011 в 10:45
поделиться

7 ответов

Исходя из того, что я сижу, обычные для циклов умеренно быстрее, чем для каждого циклов в минимальном случае. Также, как и в случае с 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: Ответы на комментарий Ошышко:

  1. Компилятор мог пропускать обращения к моим внутренним циклам, но это не так. Циклы завершились бы в два или три раза быстрее, если бы это было так.
  2. Результаты изменились в опубликованном вами примере кода, потому что в этой версии цикл for теперь имеет неявное преобразование типов. Я оставил задания вне цикла, чтобы этого избежать. Конечно, можно возразить, что допустимо использовать дополнительное приведение в цикле for , потому что «реальный код» все равно понадобится, но для меня это просто еще один способ сказать «нет общего ответа; какой цикл быстрее зависит от того, что вы делаете внутри своего цикла ". Вот ответ, который я вам даю. ;)
23
ответ дан 30 November 2019 в 21:54
поделиться

for будет быстрее для массивов ... но в зависимости от ситуации лучше всего использовать foreach ... см. Этот эталонный тест .net .

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

1
ответ дан 30 November 2019 в 21:54
поделиться

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

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

greetz

back2dos

-4
ответ дан 30 November 2019 в 21:54
поделиться

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

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 - заметно быстрее (хотя, тем не менее, для каждого удара while):

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

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

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

forEachLoop: 328 whileLoop: 366

forEachLoop: 324 whileLoop: 369

2
ответ дан 30 November 2019 в 21:54
поделиться

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

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" вы получите "лежачий полицейский" (75 мс вместо 105 мс):

2
ответ дан 30 November 2019 в 21:54
поделиться

Просто дополнение:

a для каждого ... в цикле не гарантирует Вам, что элементы в массиве / векторе перечисляются в ПОРЯДКЕ, В котором ОНИ ХРАНИТСЯ. (кроме XML) Это существенная разница, ИМО.

"... Следовательно, вы не должны писать код, который зависит от порядок перечисления каждого входящего или входящего цикла, если вы не обрабатываете XML-данные ... "C.Moock

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

Удачного тестирования.

-1
ответ дан 30 November 2019 в 21:54
поделиться

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

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

.
0
ответ дан 30 November 2019 в 21:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: