Сегодня я протестировал влияние запросов 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 - при увеличении числа делегатов выбора?
Math.Sqrt
не подходят для PLINQ, поскольку они тривиальны (слишком быстры). Чем дороже, тем лучше. msdn.microsoft.com/en-us/library/dd997399.aspx Возможно, вы также захотите взглянуть на мой вопрос здесь, я перечислил некоторые рекомендуемые чтения. - person Tim Schmelter   schedule 24.08.2012