В .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 ]

4 голосов
/ 22 сентября 2018

Вы можете прочитать об этом в Deep .NET - часть 1 Итерация

это покрытие результатов (без первой инициализации) из исходного кода .NET вплоть до разборки.

например - Итерация массива с циклом foreach: enter image description here

и - итерация списка с циклом foreach: enter image description here

и конечные результаты: enter image description here

enter image description here

3 голосов
/ 23 января 2009

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

Если итератор уже настроен, как, например, с одним из классов коллекции, тогда foreach является хорошим простым вариантом. И если вы перебираете целочисленный диапазон, то, вероятно, он чище.

3 голосов
/ 23 января 2009

Джеффри Рихтер рассказал о разнице в производительности между for и foreach в недавнем подкасте: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317

3 голосов
/ 12 июня 2014

Я обнаружил цикл foreach, который перебирает List быстрее . Смотрите результаты моего теста ниже. В приведенном ниже коде я итерирую array размером 100, 10000 и 100000 отдельно, используя цикл for и foreach для измерения времени.

enter image description here

private static void MeasureTime()
    {
        var array = new int[10000];
        var list = array.ToList();
        Console.WriteLine("Array size: {0}", array.Length);

        Console.WriteLine("Array For loop ......");
        var stopWatch = Stopwatch.StartNew();
        for (int i = 0; i < array.Length; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("Array Foreach loop ......");
        var stopWatch1 = Stopwatch.StartNew();
        foreach (var item in array)
        {
            Thread.Sleep(1);
        }
        stopWatch1.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List For loop ......");
        var stopWatch2 = Stopwatch.StartNew();
        for (int i = 0; i < list.Count; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch2.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List Foreach loop ......");
        var stopWatch3 = Stopwatch.StartNew();
        foreach (var item in list)
        {
            Thread.Sleep(1);
        }
        stopWatch3.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds);
    }

ОБНОВЛЕНО

После предложения @jgauffin я использовал код @johnskeet и обнаружил, что цикл for с array быстрее, чем следующий,

  • Цикл Foreach с массивом.
  • Для цикла со списком.
  • цикл по каждому элементу со списком.

См. Мои результаты испытаний и код ниже,

enter image description here

private static void MeasureNewTime()
    {
        var data = new double[Size];
        var rng = new Random();
        for (int i = 0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }
        Console.WriteLine("Lenght of array: {0}", data.Length);
        Console.WriteLine("No. of iteration: {0}", Iterations);
        Console.WriteLine(" ");
        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with Array: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (var i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with Array: {0}", sw.ElapsedMilliseconds);
        Console.WriteLine(" ");

        var dataList = data.ToList();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < dataList.Count; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in dataList)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds);
    }
3 голосов
/ 22 декабря 2009

На самом деле винт с его головой и пойти вместо IQueryable .foreach закрытия:

myList.ForEach (c => Console.WriteLine (c.ToString ());

LOL * * 1005

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

В большинстве случаев нет никакой разницы.

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

Можно утверждать, что циклы for могут быть немного сложнее поддерживать, если в коде начинают появляться магические числа. Вы должны быть правы, если будете раздражены тем, что не можете использовать цикл for и должны собирать коллекцию или использовать лямбду для создания подколлекции вместо этого только потому, что циклы for были запрещены.

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

for имеет более простую логику для реализации, поэтому она быстрее, чем foreach.

2 голосов
/ 23 января 2009

Я бы не ожидал, что кто-то обнаружит "огромную" разницу в производительности между ними.

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

Конечно, этот ответ не учитывает оптимизацию, которую может реализовать компилятор.

2 голосов
/ 17 февраля 2009

Имейте в виду, что цикл for и цикл foreach не всегда эквивалентны. Перечислители списка будут генерировать исключение, если список изменится, но вы не всегда получите это предупреждение с обычным циклом for. Вы можете даже получить другое исключение, если список меняется не вовремя.

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

Кажется немного странным полностью запретить использование чего-то вроде цикла for.

Здесь есть интересная статья , в которой освещается большая разница в производительности между двумя циклами.

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

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