.net 4.0 对于这段代码,为什么PLINQ比LINQ慢?

.net 4.0 对于这段代码,为什么PLINQ比LINQ慢?,.net-4.0,parallel-processing,plinq,.net 4.0,Parallel Processing,Plinq,首先,我在一台双核2.66Ghz处理器机器上运行它。我不确定.AsParallel()调用是否在正确的位置。我也直接在范围变量上进行了尝试,但速度仍然较慢。我不明白为什么 以下是我的结果: 进程非并行1000花费了146毫秒 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace DemoConsoleApp { internal class

首先,我在一台双核2.66Ghz处理器机器上运行它。我不确定.AsParallel()调用是否在正确的位置。我也直接在范围变量上进行了尝试,但速度仍然较慢。我不明白为什么

以下是我的结果:

进程非并行1000花费了146毫秒

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);
    }
  }
}
进程并行1000花费了156毫秒

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);
    }
  }
}
进程非并行5000花费了5187毫秒

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);
    }
  }
}
进程并行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);
    }
  }
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
名称空间DemoConsoleApp
{
内部课程计划
{
私有静态void Main()
{
ReportOnTimedProcess(
()=>GetIntegerCombinations(),
“非平行1000”);
ReportOnTimedProcess(
()=>GetIntegerCombinations(runAsParallel:true),
“平行1000”);
ReportOnTimedProcess(
()=>GetIntegerCombinations(5000),
“非平行5000”);
ReportOnTimedProcess(
()=>GetIntegerCombinations(5000,true),
“平行5000”);
Console.Read();
}
私有静态列表GetIntegerCombinations(
int iterationCount=1000,bool runAsParallel=false)
{
IEnumerable range=Enumerable.range(1,迭代计数);
IEnumerable整数组合=
从范围内的x开始
在范围内从y开始
选择新元组(x,y);
返回运行通道
?integerCombinations.AsParallel().ToList()
:integerCombinations.ToList();
}
私有静态void ReportOnTimedProcess(
操作进程,字符串(进程名称)
{
var stopwatch=新秒表();
秒表。开始();
过程();
秒表;
WriteLine(“进程{0}花费了{1}毫秒”,
进程名称,秒表。ElapsedMilliseconds);
}
}
}

它稍微慢一点,因为PLINQ有一定的开销(线程、调度等),所以您必须仔细选择要并行化的内容。您正在进行基准测试的特定代码实际上不值得并行化,您必须对负载较大的任务进行并行化,否则开销将超过并行化的好处。

您在这里的大部分执行时间可能是通过
ToList()实际创建列表
方法。这将需要执行几次内存分配、调整列表大小等等。在这里,并行化也没有带来太多好处,因为最后的操作必须同步(在输出上构建一个列表)

试着在并行段中做一些更复杂/更昂贵的事情,比如素数分解,并将迭代次数增加到数十万次(在分析时使用5000是一个非常小的数字)。那么你应该开始看到区别了


还要确保在发布模式下进行评测;我经常看到尝试在调试模式下进行评测,结果并不准确。

当迭代计数设置为5000(5000*5000)时,我的示例中的代码实际上会创建2500万个元组组合。我想我看到的问题是,每个逻辑迭代太小,无法并行。谢谢