Почему цикл для объекта массива с `foreach` быстрее, чем лямбда` ForEach`? - программирование
Подтвердить что ты не робот

Почему цикл для объекта массива с `foreach` быстрее, чем лямбда` ForEach`?

Я работаю над массивом, и я должен его перебирать. Во-первых, я использую lambda ForEach

Array
.ForEach<int>( array, ( int counter ) => {
    Console.WriteLine( counter ); 
} );

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

почему цикл для объекта массива с ForEach быстрее, чем lambda ForEach? Обновить: Я тестирую массив

4b9b3361

Ответ 1

Я немного изменил код Keith - на моей машине foreach выполнялся примерно в шесть раз быстрее, чем Array.ForEach:

class Program
{
    static void Main(string[] args)
    {
        Benchmark(50);
    }

    private static void Benchmark(int iterations)
    {
        int[] list = Enumerable.Range(0, 100000000).ToArray();

        long sum = 0;
        for (int i = 0; i < iterations; i++)
        {
            sum += ArrayForeach(list);
        }

        Console.WriteLine("ForEach " + sum / iterations);

        sum = 0;
        for (int i = 0; i < iterations; i++)
        {
            sum += Foreach(list);
        }

        Console.WriteLine("foreach " + sum / iterations);
    }

    private static long Foreach(int[] list)
    {
        long total = 0;
        var stopWatch = Stopwatch.StartNew();
        foreach (var i in list)
        {
            total += i;
        }
        stopWatch.Stop();
        return stopWatch.ElapsedTicks;
    }

    private static long ArrayForeach(int[] list)
    {
        long total = 0;
        var stopWatch = Stopwatch.StartNew();
        Array.ForEach(list, x => total += x);
        stopWatch.Stop();
        return stopWatch.ElapsedTicks;
    }
}

На моей машине (которая может запускать другую CLR, чем другие) она производит (в Release):

ForEach 695910  
foreach 123852  

В отладке:

ForEach 941030
foreach 845443
  • Это показывает, что foreach пользуется некоторыми оптимизациями компилятора, я предполагаю, что в основном это касается доступа к списку в памяти.
  • В Debug это выглядит как накладные расходы на запуск лямбда, и передача количества (по значению) отвечает за разницу.

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

Ответ 2

Я нахожу лямбду быстрее в своем тестировании. Скопируйте вставку кода секундомера MSDN и украшаем его двумя версиями итерации списка.... (Я также изменил порядок тестирования, и я получаю одинаковые тайминги). Итерация Linq с лямбдой идет быстрее.

Lambda  00:00:00.49
foreach 00:00:00.58

и код..

var list = Enumerable.Range(0, 100000000).ToArray();
        var total = 0;
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        Array.ForEach(list, x => total += x);

        stopWatch.Stop();
        TimeSpan ts = stopWatch.Elapsed;
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds / 10);
        Console.WriteLine("RunTime " + elapsedTime);


        stopWatch = new Stopwatch();
        stopWatch.Start();
        foreach (var i in list)
        {
            total += i;
        }      
        stopWatch.Stop();
        // Get the elapsed time as a TimeSpan value.
        ts = stopWatch.Elapsed;

        // Format and display the TimeSpan value. 
        elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds / 10);
        Console.WriteLine("RunTime " + elapsedTime);