В C # / VB.NET / .NET какой цикл работает быстрее for
или foreach
?
С тех пор, как я прочитал, что for
цикл работает быстрее, чем foreach
цикл давным-давно, я предположил, что это верно для всех коллекций, универсальных коллекций, всех массивов и т. Д.
Я просмотрел Google и нашел несколько статей, но большинство из них неубедительны (читай комментарии к статьям) и открыты.
Что было бы идеально, так это иметь каждый сценарий в списке и лучшее решение для него.
Например (просто пример того, как это должно быть):
- для перебора массива из 1000+ строк -
for
лучше, чемforeach
- для перебора
IList
(не универсальных) строк -foreach
лучше, чемfor
Несколько ссылок, найденных в Интернете для того же:
- Оригинальная старая статья Эммануэля Шанцера
- CodeProject FOREACH Vs. ДЛЯ
- Блог - к
foreach
или нетforeach
, вот в чем вопрос - Форум ASP.NET - NET 1.1 C #
for
противforeach
[Редактировать]
Помимо аспекта читабельности, меня действительно интересуют факты и цифры. Существуют приложения, в которых важна последняя миля оптимизации производительности.
c#
.net
performance
for-loop
Binoj Antony
источник
источник
foreach
вместоfor
C #. Если вы видите здесь ответы, которые вообще не имеют смысла, вот почему. Виноват модератор, а не несчастные ответы.Ответы:
Об этом в прошлом месяце написал Патрик Смаккья со следующими выводами:
источник
foreach
чем для обхода массиваfor
, и вы называете это незначительным? Такая разница в производительности может иметь значение для вашего приложения, а может и нет, но я бы просто не отмахнулся от нее.foreach
s.Сначала встречный иск к ответу Дмитрия (теперь удален) . Для массивов компилятор C # выдает в основном тот же код,
foreach
что и для эквивалентногоfor
цикла. Это объясняет, почему для этого теста результаты в основном такие же:Полученные результаты:
Далее, проверка того, что Грег говорит о важности типа коллекции - измените массив на a
List<double>
в приведенном выше, и вы получите радикально разные результаты. Это не только значительно медленнее в целом, но foreach становится значительно медленнее, чем доступ по индексу. Сказав это, я все равно почти всегда предпочитаю foreach циклу for, где он упрощает код - потому что читаемость почти всегда важна, а микрооптимизация редко.источник
List<T>
? Читаемость также превосходит микрооптимизацию в этом случае?List<T>
массивы. Исключенияchar[]
иbyte[]
которые чаще рассматриваются как «куски» данные , а не обычные коллекции.foreach
циклы демонстрируют более конкретное намерение, чемfor
циклы .Использование
foreach
цикла демонстрирует любому, кто использует ваш код, что вы планируете что-то сделать для каждого члена коллекции независимо от его места в коллекции. Это также показывает, что вы не изменяете исходную коллекцию (и выдает исключение, если вы пытаетесь это сделать).Другое преимущество
foreach
заключается в том, что он работает в любом местеIEnumerable
, гдеfor
имеет смысл только тоIList
, где каждый элемент имеет индекс.Однако, если вам нужно использовать индекс элемента, тогда, конечно, вам должно быть разрешено использовать
for
цикл. Но если вам не нужно использовать индекс, его наличие просто загромождает ваш код.Насколько я знаю, никаких существенных последствий для производительности нет. На каком-то этапе в будущем будет проще адаптировать код
foreach
для работы на нескольких ядрах, но сейчас не о чем беспокоиться.источник
foreach
.foreach
нисколько не связано с функциональным программированием. Это абсолютно обязательная парадигма программирования. Вы неправильно приписываете вещи, происходящие в TPL и PLINQforeach
.foreach
как эквивалентwhile
цикла). Я думаю, я знаю, что @ctford имеет в виду. Задача параллельной библиотеки позволяет базовой коллекции предоставлять элементы в произвольном порядке (путем вызова.AsParallel
перечислимого).foreach
здесь ничего не делается, и тело цикла выполняется в одном потоке . Единственное, что распараллелено, - это генерация последовательности.foreach
иfor
производительностью для обычных списков составляет доли секунды для итерации по миллионам элементов, поэтому ваша проблема, безусловно, не была напрямую связана с производительностью foreach, по крайней мере, с несколькими сотнями объектов. Походит на сломанную реализацию перечислителя в любом списке, который вы использовали.Каждый раз, когда возникают споры по поводу производительности, вам просто нужно написать небольшой тест, чтобы вы могли использовать количественные результаты для поддержки вашего случая.
Используйте класс StopWatch и повторите что-то несколько миллионов раз для точности. (Это может быть трудно без цикла for):
Пальцы пересекли результаты этого шоу, что разница незначительна, и вы могли бы просто сделать любые результаты в наиболее поддерживаемом коде
источник
Это всегда будет близко. Для массива иногда
for
немного быстрее, ноforeach
он более выразителен и предлагает LINQ и т. Д. В общем, придерживайтесьforeach
.Кроме того,
foreach
может быть оптимизирован в некоторых сценариях. Например, связанный список может быть ужасным для индексатора, но он может быть быстрымforeach
. На самом деле, стандартLinkedList<T>
даже не предлагает индексатор по этой причине.источник
LinkedList<T>
что стройнее, чемList<T>
? И если я всегда буду использоватьforeach
(вместоfor
), мне лучше использоватьLinkedList<T>
?List<T>
). Больше того, что дешевле вставить / удалить .Я предполагаю, что это, вероятно, не будет значимым в 99% случаев, так почему бы вам выбрать более быстрый, а не наиболее подходящий (как это проще всего понять / сохранить)?
источник
Вряд ли между ними будет огромная разница в производительности. Как всегда, когда сталкиваешься с "что быстрее?" Вопрос, вы всегда должны думать: «Я могу измерить это».
Напишите два цикла, которые делают одно и то же в теле цикла, выполните и рассчитайте их оба, и посмотрите, какова разница в скорости. Делайте это как с почти пустым телом, так и с телом цикла, похожим на то, что вы на самом деле будете делать. Также попробуйте это с типом коллекции, который вы используете, потому что разные типы коллекций могут иметь разные характеристики производительности.
источник
Есть очень веские причины, чтобы предпочесть
foreach
петли надfor
петлями. Если вы можете использоватьforeach
петлю, ваш босс прав, что вы должны.Однако не каждая итерация просто просматривает список по порядку. Если он запрещает , да, это неправильно.
На вашем месте я бы превратил все ваши естественные циклы в рекурсию . Это научит его, и это также хорошее умственное упражнение для вас.
источник
for
циклами иforeach
циклами по производительности?Джеффри Рихтер на TechEd 2005:
Веб-трансляция по требованию: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US
источник
Это смешно. Нет никаких веских причин, чтобы запретить цикл, производительность или другие.
См . Блог Джона Скита для оценки производительности и других аргументов.
источник
В случаях, когда вы работаете с коллекцией объектов,
foreach
это лучше, но если вы увеличиваете число,for
цикл лучше.Обратите внимание, что в последнем случае вы можете сделать что-то вроде:
Но он, конечно, не работает лучше, на самом деле он хуже по сравнению с
for
.источник
Это должно спасти вас:
Использование:
Для большего выигрыша вы можете взять трех делегатов в качестве параметров.
источник
for
цикл обычно пишется для исключения конца диапазона (например0 <= i < 10
).Parallel.For
также делает это, чтобы держать его легко взаимозаменяемым с общимfor
циклом.Вы можете прочитать об этом в Deep .NET - часть 1 Итерация
он охватывает результаты (без первой инициализации) из исходного кода .NET вплоть до разборки.
например - Итерация массива с циклом foreach:
и - список итераций с циклом foreach:
и конечные результаты:
источник
Различия в скорости в
for
- иforeach
-loop крошечные, когда вы просматриваете общие структуры, такие как массивы, списки и т. Д., И делаетеLINQ
запроса к коллекции почти всегда немного медленнее, хотя писать приятнее! Как говорили другие авторы, стремитесь к выразительности, а не к миллисекунде дополнительной производительности.До сих пор не было сказано, что когда
foreach
цикл компилируется, он оптимизируется компилятором на основе коллекции, по которой он перебирает. Это означает, что когда вы не уверены, какой цикл использовать, вы должны использоватьforeach
цикл - он сгенерирует лучший цикл для вас, когда будет скомпилирован. Это также более читабельно.Другое ключевое преимущество
foreach
цикла состоит в том, что если ваша реализация коллекции изменится (например, с intarray
на aList<int>
), то вашforeach
цикл не потребует никаких изменений кода:Выше приведено одно и то же, независимо от типа вашей коллекции, тогда как в вашем
for
цикле следующее не будет построено, если вы изменилиmyCollection
с aarray
на aList
:источник
«Есть ли какие-либо аргументы, которые я мог бы использовать, чтобы убедить его, что цикл for приемлем для использования?»
Нет, если ваш начальник на микроуровне говорит о том, какой язык программирования использовать, вам нечего сказать. Сожалею.
источник
Вероятно, это зависит от типа коллекции, которую вы перечисляете, и от реализации ее индексатора. В целом, использование
foreach
, вероятно, будет лучшим подходом.Кроме того, он будет работать с любыми
IEnumerable
- не только с индексаторами.источник
На это есть те же два ответа, что и на большинство вопросов «что быстрее»:
1) Если вы не измеряете, вы не знаете.
2) (потому что ...) Это зависит.
Это зависит от того, насколько дорогой метод "MoveNext ()", относительно того, насколько дорогой метод "this [int index]", для типа (или типов) IEnumerable, который вы будете перебирать.
Ключевое слово «foreach» является сокращением для ряда операций - оно вызывает GetEnumerator () один раз в IEnumerable, оно вызывает MoveNext () один раз за итерацию, выполняет некоторую проверку типов и так далее. Наиболее вероятным фактором, влияющим на измерения производительности, является стоимость MoveNext (), поскольку она вызывается O (N) раз. Может быть, это дешево, но, возможно, это не так.
Ключевое слово «for» выглядит более предсказуемым, но внутри большинства циклов «for» вы найдете что-то вроде «collection [index]». Это похоже на простую операцию индексации массива, но на самом деле это вызов метода, стоимость которого полностью зависит от природы коллекции, для которой вы выполняете итерацию. Возможно, это дешево, но, возможно, это не так.
Если базовая структура коллекции по сути представляет собой связанный список, MoveNext является дешевым, но индексатор может иметь стоимость O (N), что составляет истинную стоимость цикла for (O * N).
источник
Каждая языковая конструкция имеет подходящее время и место для использования. Есть причина, по которой язык C # имеет четыре отдельных итерационных оператора - каждый из них предназначен для определенной цели и имеет соответствующее применение.
Я рекомендую сесть с вашим боссом и попытаться рационально объяснить, почему у
for
петли есть цель. Есть моменты, когдаfor
итерационный блок более четко описывает алгоритм, чемforeach
итерация. Когда это правда, уместно использовать их.Я также хотел бы отметить вашего босса - производительность не является и не должна быть проблемой в практическом плане - это скорее вопрос выражения алгоритма в сжатой, содержательной и понятной форме. Подобные микрооптимизации полностью упускают смысл оптимизации производительности, поскольку любое реальное преимущество в производительности будет достигнуто за счет алгоритмического реорганизации и рефакторинга, а не реструктуризации цикла.
Если после разумного обсуждения все еще существует авторитарный взгляд, то вам решать, как действовать дальше. Лично я не был бы счастлив работать в среде, где рациональное мышление не поощрялось, и подумал бы о переходе на другую должность под другого работодателя. Тем не менее, я настоятельно рекомендую обсудить до того, как расстроиться - может быть просто недоразумение.
источник
Именно то, что вы делаете внутри цикла, влияет на производительность, а не на фактическую конструкцию цикла (если ваш случай нетривиален).
источник
Будь
for
быстрее, чемforeach
на самом деле, кроме сути. Я серьезно сомневаюсь, что выбор одного из других окажет значительное влияние на вашу производительность.Лучший способ оптимизировать ваше приложение - это профилирование реального кода. Это позволит точно определить методы, на которые приходится больше всего работы / времени. Оптимизируйте те сначала. Если производительность по-прежнему не приемлема, повторите процедуру.
Как правило, я бы рекомендовал держаться подальше от микрооптимизаций, поскольку они редко приносят какие-либо существенные выгоды. Единственное исключение - при оптимизации идентифицированных «горячих путей» (т. Е. Если ваше профилирование идентифицирует несколько широко используемых методов, возможно, имеет смысл оптимизировать их экстенсивно).
источник
for
незначительно быстрее, чемforeach
. Я серьезно возражаю против этого заявления. Это полностью зависит от основной коллекции. Если класс связанного списка предоставляет индексатору с целочисленным параметром, я ожидал бы, что использованиеfor
цикла для него будет O (n ^ 2), в то времяforeach
как ожидается, что O (n).for
и поиск индексатора с использованиемforeach
отдельно. Я думаю, что ответ @Brian Rasmussen правильный, что, помимо любого использования с коллекцией,for
всегда будет немного быстрее, чемforeach
. Тем не менее,for
поиск коллекции всегда будет медленнее, чемforeach
сам по себе.for
оператора используется индексатор . Обычныйfor
цикл с целочисленной переменной управления не сравним сforeach
, так что нет. Я понимаю, что означает @Brian, и, как вы говорите, это правильно, но ответ может вводить в заблуждение. Re: ваш последний пункт: нет, на самом деле,for
по-List<T>
прежнему быстрее, чемforeach
.Два будут работать практически одинаково. Напишите некоторый код, чтобы использовать оба, затем покажите ему IL. Он должен показывать сопоставимые вычисления, что означает отсутствие различий в производительности.
источник
for имеет более простую логику для реализации, поэтому она быстрее, чем foreach.
источник
Если вы не участвуете в конкретном процессе оптимизации скорости, я бы сказал, что используйте тот метод, который позволяет легко читать и поддерживать код.
Если итератор уже настроен, как, например, с одним из классов коллекции, тогда foreach является хорошим простым вариантом. И если вы перебираете целочисленный диапазон, то, вероятно, он чище.
источник
Джеффри Рихтер рассказал о разнице в производительности между for и foreach в недавнем подкасте: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317
источник
В большинстве случаев нет никакой разницы.
Как правило, вы всегда должны использовать foreach, когда у вас нет явного числового индекса, и вы всегда должны использовать его, когда у вас фактически нет итеративной коллекции (например, итерации по двумерной сетке массива в верхнем треугольнике) , В некоторых случаях у вас есть выбор.
Можно утверждать, что циклы for могут быть немного сложнее поддерживать, если в коде начинают появляться магические числа. Вы должны быть правы, если будете раздражены тем, что не можете использовать цикл for и должны собирать коллекцию или использовать лямбду для создания подколлекции вместо этого только потому, что циклы for были запрещены.
источник
Кажется немного странным полностью запретить использование чего-то вроде цикла for.
Там интересная статья здесь , которая охватывает много различий в производительности между двумя петлями.
Я бы сказал, что лично я нахожу foreach немного более читаемым для циклов, но вы должны использовать лучшее для текущей работы и не нужно писать слишком длинный код для включения цикла foreach, если цикл for более уместен.
источник
Я нашел
foreach
цикл, который перебираетList
быстрее . Смотрите результаты моего теста ниже. В приведенном ниже коде я выполняю итерацииarray
размером 100, 10000 и 100000 по отдельности, используя циклfor
иforeach
цикл для измерения времени.ОБНОВЛЕНО
После предложения @jgauffin я использовал код @johnskeet и обнаружил, что
for
цикл сarray
более быстрым, чем следующий,Смотрите результаты моего теста и код ниже,
источник
Вы можете действительно ввернуть его голову и пойти на IQueryable .foreach закрытие вместо этого:
источник
myList.ForEach(Console.WriteLine)
.Я не ожидал бы, что кто-нибудь найдет "огромную" разницу в производительности между этими двумя.
Я предполагаю, что ответ зависит от того, имеет ли доступ к коллекции, к которой вы пытаетесь получить, более быструю реализацию доступа к индексаторам или более быструю реализацию доступа IEnumerator. Поскольку IEnumerator часто использует индексатор и просто хранит копию текущей позиции индекса, я ожидаю, что доступ к перечислителю будет, по крайней мере, таким же медленным или медленным, как прямой доступ к индексу, но ненамного.
Конечно, этот ответ не учитывает никаких оптимизаций, которые может реализовать компилятор.
источник
Имейте в виду, что цикл for и цикл foreach не всегда эквивалентны. Перечислители списка будут генерировать исключение, если список изменится, но вы не всегда получите это предупреждение с обычным циклом for. Вы можете даже получить другое исключение, если список меняется не вовремя.
источник