В .NET какой цикл выполняется быстрее, «для» или «foreach»? - PullRequest
311 голосов
/ 13 декабря 2008

В C # / VB.NET / .NET цикл работает быстрее, for или foreach?

С тех пор, как я прочитал, что цикл for работает быстрее, чем цикл foreach давно Я предположил, что это верно для всех коллекций, общих коллекций, всех массивов и т. Д.

Я искал Google и нашел несколько статей, но большинство из них неубедительны (см. Комментарии к статьям) и имеют открытый конец.

Что было бы идеально, так это перечислить каждый сценарий и найти лучшее решение для него.

Например (просто пример того, как это должно быть):

  1. для итерации массива 1000+ строки - for лучше, чем foreach
  2. для итерации по IList (не универсальным) строкам - foreach лучше чем for

В Интернете найдено несколько ссылок на одно и то же:

  1. Оригинальная великая старая статья Эммануэля Шанцера
  2. CodeProject FOREACH Vs. ДЛЯ
  3. Блог - foreach или foreach, вот в чем вопрос
  4. Форум ASP.NET - NET 1.1 C # for против foreach

[Изменить]

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

Ответы [ 40 ]

11 голосов
/ 22 декабря 2009

В тех случаях, когда вы работаете с коллекцией объектов, foreach лучше, но если вы увеличиваете число, цикл for лучше.

Обратите внимание, что в последнем случае вы можете сделать что-то вроде:

foreach (int i in Enumerable.Range(1, 10))...

Но, конечно, он не работает лучше, на самом деле он хуже по сравнению с for.

10 голосов
/ 22 декабря 2009

Это должно спасти вас:

public IEnumerator<int> For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

Использование:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

Для большего выигрыша вы можете взять в качестве параметров трех делегатов.

7 голосов
/ 13 ноября 2014

На это есть те же два ответа, что и на большинство вопросов «что быстрее»:

1) Если вы не измеряете, вы не знаете.

2) (потому что ...) Это зависит.

Это зависит от того, насколько дорогой метод "MoveNext ()", относительно того, насколько дорогой метод "this [int index]", для типа (или типов) IEnumerable, который вы будете перебирать.

Ключевое слово "foreach" является сокращением для ряда операций - оно вызывает GetEnumerator () один раз в IEnumerable, оно вызывает MoveNext () один раз за итерацию, выполняет некоторую проверку типов и так далее. Наиболее вероятным фактором, влияющим на измерения производительности, является стоимость MoveNext (), поскольку она вызывается O (N) раз. Может быть, это дешево, но, возможно, это не так.

Ключевое слово "for" выглядит более предсказуемым, но внутри большинства циклов "for" вы найдете что-то вроде "collection [index]". Это похоже на простую операцию индексации массива, но на самом деле это вызов метода, стоимость которого полностью зависит от природы коллекции, для которой вы выполняете итерацию. Возможно, это дешево, но, возможно, это не так.

Если базовая структура коллекции, по сути, является связанным списком, MoveNext очень дешев, но индексатор может иметь стоимость O (N), что составляет истинную стоимость цикла "for" O (N * N).

7 голосов
/ 13 декабря 2008

Различия в скорости в for - и foreach -петлях крошечные, когда вы просматриваете общие структуры, такие как массивы, списки и т. Д., И выполнение запроса LINQ по коллекции почти всегда немного медленнее, хотя писать приятнее! Как говорилось в других постерах, стремитесь к выразительности, а не к миллисекунде дополнительной производительности.

Что еще не было сказано, так это то, что когда цикл foreach компилируется, он оптимизируется компилятором на основе коллекции, которую он перебирает. Это означает, что когда вы не уверены, какой цикл использовать, вы должны использовать цикл foreach - он сгенерирует лучший цикл для вас, когда будет скомпилирован. Это также более читабельно.

Другое ключевое преимущество цикла foreach состоит в том, что если ваша реализация коллекции изменится (например, с int array на List<int>), то ваш цикл foreach не потребует никаких изменений кода:

foreach (int i in myCollection)

Выше приведено одно и то же, независимо от типа вашей коллекции, тогда как в цикле for следующее не будет построено, если вы изменили myCollection с array на List:

for (int i = 0; i < myCollection.Length, i++)
7 голосов
/ 23 января 2009

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

Кроме того, он будет работать с любыми IEnumerable - не только с индексаторами.

7 голосов
/ 22 декабря 2009

«Есть ли какие-либо аргументы, которые я мог бы использовать, чтобы убедить его, что цикл for допустим?»

Нет, если ваш начальник на микроуровне говорит вам о том, какой язык программирования используется для построения, вам действительно нечего сказать. К сожалению.

6 голосов
/ 22 декабря 2009

Каждая языковая конструкция имеет подходящее время и место для использования. Существует причина, по которой язык C # имеет четыре отдельных итерационных оператора - каждый из них предназначен для определенной цели и имеет соответствующее использование.

Я рекомендую сесть с вашим боссом и попытаться рационально объяснить, почему у петли for есть цель. Бывают моменты, когда итерационный блок for более четко описывает алгоритм, чем итерация foreach. Когда это правда, уместно использовать их.

Я бы также указал вашему боссу - производительность не является и не должна быть проблемой на практике - это скорее вопрос выражения алгоритма в сжатой, содержательной и понятной форме. Подобные микрооптимизации полностью упускают смысл оптимизации производительности, поскольку любое реальное преимущество в производительности будет достигнуто за счет алгоритмического реорганизации и рефакторинга, а не реструктуризации цикла.

Если после рационального обсуждения все еще сохраняется авторитарный взгляд, то вам решать, как действовать дальше. Лично я не был бы счастлив работать в среде, где рациональное мышление не поощрялось, и подумал бы о переходе на другую должность под другого работодателя. Тем не менее, я настоятельно рекомендую обсудить это до того, как расстроиться - может произойти простое недоразумение.

5 голосов
/ 22 декабря 2009

Это то, что вы делаете внутри цикла, который влияет на производительность, а не фактическую конструкцию цикла (при условии, что ваш случай нетривиален).

5 голосов
/ 22 декабря 2009

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

Лучший способ оптимизировать ваше приложение - это профилирование реального кода. Это позволит точно определить методы, на которые приходится больше всего работы / времени. Оптимизируйте те сначала. Если производительность по-прежнему не приемлема, повторите процедуру.

Как правило, я бы рекомендовал держаться подальше от микрооптимизаций, так как они редко приносят какие-либо существенные выгоды. Единственное исключение - при оптимизации идентифицированных «горячих путей» (т. Е. Если в вашем профилировании идентифицировано несколько широко используемых методов, возможно, имеет смысл значительно их оптимизировать).

4 голосов
/ 22 декабря 2009

Два будут работать почти одинаково. Напишите некоторый код, чтобы использовать оба, а затем покажите ему IL. Он должен показывать сопоставимые вычисления, что означает отсутствие различий в производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...