2010-04-10 2 views
2

Во-первых, я запускаю это на двухъядерном процессоре процессора 2,66 ГГц. Я не уверен, есть ли у меня вызов .AsParallel() в правильном месте. Я тоже пробовал его непосредственно в переменной диапазона, и это было еще медленнее. Я не понимаю, почему ...Почему PLINQ медленнее LINQ для этого кода?

Вот мои результаты:

Процесс непараллельный 1000 приняли 146 миллисекунды

процесс параллельной 1000 принял 156 миллисекунды

процесса непараллельный 5000 принимали 5187 миллисекунды

процесс параллельной 5000 взял 5300 миллисекунды

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

namespace DemoConsoleApp 
{ 
    internal class Program 
    { 
    private static void Main() 
    { 
     ReportOnTimedProcess(
     () => GetIntegerCombinations(), 
     "non-parallel 1000"); 

     ReportOnTimedProcess(
     () => GetIntegerCombinations(runAsParallel: true), 
     "parallel 1000"); 

     ReportOnTimedProcess(
     () => GetIntegerCombinations(5000), 
     "non-parallel 5000"); 

     ReportOnTimedProcess(
     () => GetIntegerCombinations(5000, true), 
     "parallel 5000"); 

     Console.Read(); 
    } 

    private static List<Tuple<int, int>> GetIntegerCombinations(
     int iterationCount = 1000, bool runAsParallel = false) 
    { 
     IEnumerable<int> range = Enumerable.Range(1, iterationCount); 

     IEnumerable<Tuple<int, int>> integerCombinations = 
     from x in range 
     from y in range 
     select new Tuple<int, int>(x, y); 

     return runAsParallel 
       ? integerCombinations.AsParallel().ToList() 
       : integerCombinations.ToList(); 
    } 

    private static void ReportOnTimedProcess(
     Action process, string processName) 
    { 
     var stopwatch = new Stopwatch(); 
     stopwatch.Start(); 
     process(); 
     stopwatch.Stop(); 

     Console.WriteLine("Process {0} took {1} milliseconds", 
         processName, stopwatch.ElapsedMilliseconds); 
    } 
    } 
} 

ответ

4

Это немного медленнее, потому что у PLINQ есть определенные накладные расходы (потоки, планирование и т. Д.), Поэтому вам нужно тщательно подобрать то, что вы будете распараллеливать. Этот конкретный код, который вы сравниваете, на самом деле не стоит распараллеливать, вы должны распараллеливать задачи со значительной нагрузкой, иначе накладные расходы будут весить больше, чем преимущества распараллеливания.

0

Большая часть вашего времени выполнения здесь, вероятно, будет фактически создаваться в списке, используя метод ToList(). Это должно будет выполнять несколько распределений памяти, изменение размера списка и т. Д. Вы также не получаете большую выгоду от распараллеливания здесь, потому что окончательная операция должна быть синхронизирована (вы создаете единый список на выходе).

Попробуйте сделать что-то значительно более сложное/дорогое в параллельном сегменте, например, простое факторизацию и увеличение количества итераций до сотен тысяч (5000 - это очень небольшое количество, которое нужно использовать при профилировании). Тогда вы должны увидеть разницу.

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

+1

Код в моем примере фактически создаст 25 миллионов комбинаций кортежей, когда количество итераций будет установлено в 5000 (5000 * 5000). Я думаю, что я вижу, что каждая логическая итерация слишком мала, чтобы распараллеливать в любом случае. Благодаря! –