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

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

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

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

    for (int i = 0; i  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 использовали стандартный c # под прикрытием.

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

РЕДАКТИРОВАТЬ:

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

 Thiago Custodio17 июн. 2013 г., 14:58
 Jaime Torres17 июн. 2013 г., 15:03
Он сказал вам - запустите тесты без учета времени, а затем снова запустите тесты, используя класс секундомера (точнее).
 Coltech17 июн. 2013 г., 15:00
Джон, я думаю, что ты прав. Как я могу изменить свой код, чтобы отфильтровать время JIT и получить действительные числа?
 digEmAll17 июн. 2013 г., 15:21
... и не забудьте запустить тесты вне Visual Studio или по телефону "Отладка -> Начать без отладки " даже когда вы находитесь в режиме релиза.
 Jon Skeet17 июн. 2013 г., 14:54
Вы пытались изменить порядок тестов? Вы можете видеть время JIT. Это'Как правило, лучше сначала прогнать тест, чтобы прогреть систему,затем запустите это снова и время это. Также используйте секундомер. Увидетьericlippert.com/tag/benchmarks
 Adam Houldsworth17 июн. 2013 г., 15:21
@Coltech Чтобы прогреть код, просто запустите его один раз перед запуском тестового прогона, чтобы любые вызванные методы и т. Д. Были скомпилированы JIT перед запуском тестового прогона. Когда я делаю это, я просто тестирую код в другом методе, затем вызываю метод один раз перед моим циклом синхронизации, а затем, как вы это делаете внутри цикла синхронизации.
 jackmott27 мар. 2017 г., 04:46
Как в стороне - цикл for будет повторяться быстрееList чем цикл foreach. Это не верно для массивов, с массивами это будет то же самое.
 Adam Houldsworth17 июн. 2013 г., 15:14
Кроме того, нене забудьте запустить несколько тестов и усреднить их правильно. Ваш компьютер мог работать с ошибкой, потому что Adobe запрашивала обновление во время одного из запусков, что вызывало задержку ОС в миллисекундах. Глупо, как все это звучит, такова непостоянная природа синхронизации микропроцессора в системах, управляемых прерываниями.
 Vitor Canova17 июн. 2013 г., 15:07
Дон»не забудьте забежать вRelease режим вместоDebug Режим. Это может иметь значение.

Ответы на вопрос(2)

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

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

Традиционная итерация с / без регулярных выражений

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

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

 edtheprogrammerguy17 июн. 2013 г., 16:30
Это только часть примера профилирования. Не стесняйтесь игнорировать часть Regex.
 svick17 июн. 2013 г., 16:27
Как этот вопрос связан с регулярным выражением?
Решение Вопроса

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

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
 ken2k17 июн. 2013 г., 15:22
Вы'тестируете один и тот же метод оба раза, и выВы все еще используете DateTime для получения времени ...
 Peter17 июн. 2013 г., 15:17
добавлен тест с примером кода прогрева
 ken2k17 июн. 2013 г., 15:12
Вы'мы перефразировали Джона Скитакомментарий (с меньшим количеством деталей, "разогреть" против JIT). Вы должны добавить примеры и больше объяснений ...
 Peter17 июн. 2013 г., 16:32
Изменена дата и время для реализации секундомера
 Coltech17 июн. 2013 г., 15:12
Благодарю. Я буду использовать секундомер вместо даты и времени. Не могли бы вы определить, что вы подразумеваете под "разогреть"?
 Coltech17 июн. 2013 г., 15:28
Использование этого кода и замена даты и времени на секундомер дали ожидаемые результаты. Спасибо!

Ваш ответ на вопрос