LINQ vs foreach измерение скорости работы

Я вспомнил что давно хотел прояснить для себя вопрос, насколько использование LINQ быстрее/медленнее циклов.
Оказалось, к моему сожалению что медленнее, а массивы оказались быстрее листов.
Немного вступления. Когда появился LINQ он показался мне чем-то страшным и только для работы с базами данных. Через некоторое время я полюбил его. В самом деле, писать типизированные запросы к базе данных на нам настоящее удовольствие. И так постепенно он плотно вошел в мою жизнь. Я забыл все алгоритмы сортировки и поиска и полностью стал использовать LINQ. Но никогда не задумывался, а насколько быстро он работает. И вот вечером, после прочтения статьи о том что массивы быстрее листов (я думал на оборот) я решил проверить.
Для этого быстро написал код, коллекции и массивы я решил заполнять случайными значениями, при старте приложения. Размер массивов/списков 10000000 элементов. Замеры я делал на релизном билде с отпимизацией (.net4.5).
Ну что, начнем, для начала строки:

var result = stringList.Where(w => w.Contains("ab")).ToList();

против

var result = new List<string>();
            foreach (var item in stringList)
            {
                if (item.Contains("ab"))
                {
                    result.Add(item); 
                }
            }

И что в результате?
3480 мс. против 2360 мс. 
А если в место листов используются массивы то 2542 мс. против 2122 мс.
Да, вот так, почти секунда разницы. Как вы понимаете LINQ проиграл, так же, как и листы.
Грубо говоря мы теряем 35% производительности на LINQ запросах.
На массивах мы теряем всего 15% на LINQ запросах.

Теперь числа:

var result = intList.Where(w => w > 300 && w < 1000).ToList();

против

var result = new List<int>();
            foreach (var item in intList)
            {
                if (item > 300 && item < 1000)
                {
                    result.Add(item);
                }
            }

314 мс. против 184 мс. и 188 против 165 для массивов. Ну чтож, опять LINQ проиграл. Причем разница уже в 42% для листов и 13% для массивов.
Последняя надежда остаётся FirstOrDefault() может сейчас вырваться вперед?

var result = intList.Where(w => w > 300 && w < 5000).FirstOrDefault();

против

int result = 0;
            foreach (var item in intList)
            {
                if (item > 300 && item < 5000)
                {
                    result = item;
                    break;
                }
            }

51 и 45 мс. в этот раз 22%, и  foreach опять победил.

Я запускал несколько раз приложение, и результат всегда был одинаковый от 20% до 45% процентов увеличение времени выполнения по сравнению с foreach.
Интересно, чем обусловлено такое поведение? Я думаю, что лишнее время тратиться на создания дерева выражений, и возможно какие-то еще функции.
Вот так, за красивый и хорошо читаемый код нам приходиться расплачиваться скоростью работы. С другой стороны в обычных приложениях несколько десятков миллисекунд задержки будут не критичны, но в высоконагруженных проектах это может стать большой проблемой.

 

 

Add comment

Loading