Почему LINQ быстрее в этом примере - программирование
Подтвердить что ты не робот

Почему LINQ быстрее в этом примере

Я написал следующее, чтобы проверить эффективность использования foreach vs LINQ:

private class Widget
{
    public string Name { get; set; }
}

static void Main(string[] args)
{
    List<Widget> widgets = new List<Widget>();
    int found = 0;

    for (int i = 0; i <= 500000 - 1; i++)
        widgets.Add(new Widget() { Name = Guid.NewGuid().ToString() });

    DateTime starttime = DateTime.Now;

    foreach (Widget w in widgets)
    {
        if (w.Name.StartsWith("4"))
            found += 1;
    }

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    starttime = DateTime.Now;
    found = widgets.Where(a => a.Name.StartsWith("4")).Count();

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    Console.ReadLine();
}

Я получаю что-то вроде следующего вывода:

31160 - 116ms
31160 - 95 ms

В каждом прогоне LINQ превосходит foreach примерно на 20%. Насколько я понимаю, методы расширения LINQ использовали стандартные С# под обложками.

Итак, почему LINQ быстрее в этом случае?

EDIT:

Итак, я изменил свой код на использование секундомера вместо datetime и все равно получаю те же результаты. Если я сначала запустил запрос LINQ, тогда мои результаты показывают, что LINQ будет примерно на 20% медленнее, чем foreach. Это должно быть какая-то проблема теплоснабжения JIT. Мой вопрос в том, как я могу компенсировать разминку JIT в моем тестовом случае?

4b9b3361

Ответ 1

Это потому, что у вас нет разминки. Если вы отмените свои дела, вы получите удовлетворительный результат:

31272 - 110ms
31272 - 80 ms

Начните добавлять разминку и использовать секундомер для лучшего времени.

Запуск теста с разминкой:

        //WARM UP:
        widgets.Where(a => a.Name.StartsWith("4")).Count();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }

        //RUN Test
        Stopwatch stopwatch1 = new Stopwatch();
        stopwatch1.Start();

        found = widgets.Where(a => a.Name.StartsWith("4")).Count();
        stopwatch1.Stop();

        Console.WriteLine(found + " - " + stopwatch1.Elapsed);

        found = 0;
        Stopwatch stopwatch2 = new Stopwatch();
        stopwatch2.Start();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }
        stopwatch2.Stop();

        Console.WriteLine(found + " - " + stopwatch2.Elapsed);

результат:

31039 - 00:00:00.0783508
31039 - 00:00:00.0766299

Ответ 2

Я немного прокомментировал некоторое время назад, сравнив следующее:

  • LINQ для объектов с/без регулярного выражения

  • Лямбда-выражения с/без регулярного выражения

  • Традиционная итерация с/без Regex

То, что я узнал, было то, что LINQ, Lambda и традиционная итерация были почти одинаковыми всегда, но реальная разница во времени была в выражениях Regex. Только добавление Regex делало оценку медленнее (LOT медленнее). (Подробнее здесь: http://www.midniteblog.com/?p=72)

То, что вы видите выше, вероятно, связано с тем, что вы выполняете оба теста в одном блоке кода. Попробуйте комментировать один из них, выбрав время, а затем комментируя другое. Кроме того, убедитесь, что вы используете сборку выпуска, а не в отладчике.