Производительность Linq

Сегодня я протестировал влияние запросов Linq и PLinq на производительность. Поэтому я использовал статью о msdn Как измерить производительность запросов PLINQ.

void Main()
{
        var source = Enumerable.Range(0, 600000000);
        System.Diagnostics.Stopwatch sw;    

        var queryToMeasure1 = from num in source
                             where num % 3 == 0
                             select Math.Sqrt(num);

        var queryToMeasure2 = from num in source.AsParallel()
                             where num % 3 == 0
                             select Math.Sqrt(num);                          

        long freq = Stopwatch.Frequency;
        Console.WriteLine("Timer frequency in ticks per second = {0}", freq);

        Console.WriteLine("Measuring 1");
        sw = System.Diagnostics.Stopwatch.StartNew();   
        foreach (var n in queryToMeasure1) { }  
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);      

        Console.WriteLine("Measuring 2");
        sw = System.Diagnostics.Stopwatch.StartNew();   
        foreach (var n in queryToMeasure2) { }  
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);

        Console.WriteLine("Measuring 3");
        sw = System.Diagnostics.Stopwatch.StartNew();           
        System.Threading.Tasks.Parallel.ForEach(queryToMeasure1, n => {});          
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);

        Console.WriteLine("Measuring 4");
        sw = System.Diagnostics.Stopwatch.StartNew();           
        System.Threading.Tasks.Parallel.ForEach(queryToMeasure2, n => {});      
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);

        Console.WriteLine("Measuring 5");
        sw = System.Diagnostics.Stopwatch.StartNew();   
        queryToMeasure2.ForAll(n => {});    
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds););
}

Тестовая среда: LinqPad4 на Win7 Enterprise, 64-разрядная версия, 8 ГБ ОЗУ, I7-2600 (8 ядер)

Я понял и не могу объяснить, почему запросы на одном ядре (измерение 1) быстрее, чем параллельные запросы. Нужно ли мне добавлять больше избранных делегатов, чтобы получать выгоду от параллельных задач?

Но теперь результаты:

1. Выполнить: с перечислимым диапазоном 60000:

Timer frequency in ticks per second = 3312851
Measuring 1
Total ticks: 3525 - Elapsed time: 1 ms
Measuring 2
Total ticks: 15802 - Elapsed time: 4 ms
Measuring 3
Total ticks: 5940 - Elapsed time: 1 ms
Measuring 4
Total ticks: 26862 - Elapsed time: 8 ms
Measuring 5
Total ticks: 4387 - Elapsed time: 1 ms

2. Выполнить: с перечисляемым диапазоном 600000000:

Timer frequency in ticks per second = 3312851
Measuring 1
Total ticks: 29740243 - Elapsed time: 8977 ms
Measuring 2
Total ticks: 33722438 - Elapsed time: 10179 ms
Measuring 3
Total ticks: 77145502 - Elapsed time: 23286 ms
Measuring 4
Total ticks: 120078284 - Elapsed time: 36246 ms
Measuring 5
Total ticks: 30899585 - Elapsed time: 9327 ms

Интересный факт: использование сборщика мусора перед выполнением тестового сценария значительно увеличит время измерения 4:

3. Выполнить: с перечисляемым диапазоном 600000000 и сборщиком мусора (из LinqPad):

Timer frequency in ticks per second = 3312851
Measuring 1
Total ticks: 29597830 - Elapsed time: 8934 ms
Measuring 2
Total ticks: 33532083 - Elapsed time: 10121 ms
Measuring 3
Total ticks: 76403692 - Elapsed time: 23062 ms
Measuring 4
Total ticks: 58534548 - Elapsed time: 17668 ms
Measuring 5
Total ticks: 32943622 - Elapsed time: 9944 ms

В заключение могу ли я сказать, что метод 1 является наиболее подходящим вариантом для выполнения небольших запросов на выборку, а метод 5 - при увеличении числа делегатов выбора?


person Florian    schedule 24.08.2012    source источник
comment
Modulo и Math.Sqrt не подходят для PLINQ, поскольку они тривиальны (слишком быстры). Чем дороже, тем лучше. msdn.microsoft.com/en-us/library/dd997399.aspx Возможно, вы также захотите взглянуть на мой вопрос здесь, я перечислил некоторые рекомендуемые чтения.   -  person Tim Schmelter    schedule 24.08.2012
comment
У вас есть актуальный вопрос? Или вы просто хотели начать обсуждение? Если это так, то ваш «вопрос» не подходит для SO.   -  person svick    schedule 24.08.2012
comment
Нет, я не хочу начинать обсуждение, просто хочу знать, какой метод является лучшим для выполнения огромной работы. И был не совсем уверен, были ли делегаты слишком дешевы, чтобы сделать квалифицированное заявление. Согласно msdn так и было. По словам ребят, это не   -  person Florian    schedule 24.08.2012


Ответы (1)


Ваши расчеты очень дешевы. Они даже не подходят для непараллельного LINQ, потому что вызовы делегатов могут быть дороже самих вычислений. PLINQ имеет множество дополнительных накладных расходов, таких как запуск задач, синхронизация и копирование данных между потоками. Попробуй это:

bool Where(int i) {
 var sum = 0; 
 for (10000 times) {
  sum += i;
 }
 return i % 3 == 0;
}

И используйте эту функцию в предложении where. Эта функция очень дорогая, поэтому накладные расходы, связанные с потоками и синхронизацией, больше не будут доминировать во времени выполнения.

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

person usr    schedule 24.08.2012