为什么PLINQ只使用两个线程?

时间:2009-11-28 14:40:47

标签: c# .net plinq

说我有一个IO绑定任务。我使用WithDegreeOfParallelism = 10和WithExecution = ForceParallelism模式,但查询仍然只使用两个线程。为什么呢?

我理解PLINQ通常会选择一个与我的核心数相等的并行度,但为什么它忽略了我对更高并行性的特定要求?

static void Main(string[] args)
{
    TestParallel(0.UpTo(8));
}

private static void TestParallel(IEnumerable<int> input)
{
    var timer = new Stopwatch();
    timer.Start();
    var size = input.Count();

    if (input.AsParallel().
        WithDegreeOfParallelism(10).
        WithExecutionMode(ParallelExecutionMode.ForceParallelism).
        Where(IsOdd).Count() != size / 2)
        throw new Exception("Failed to count the odds");

    timer.Stop();
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds");
}

private static bool IsOdd(int n)
{
    Thread.Sleep(1000);
    return n%2 == 1;
}

4 个答案:

答案 0 :(得分:9)

PLINQ尝试找到最佳线程数,以便尽快执行您希望它执行的操作,如果您的cpu上只有2个内核,那么这个数字很可能是2.如果您有四核,那么将更有可能看到4个线程出现,但在双核机器上创建4个线程并不能真正提高性能,因为只有2个线程可以同时处于活动状态。

此外,对于基于IO的操作,任何额外的线程都可能只是阻塞执行的第一个IO操作。

答案 1 :(得分:4)

10是最大值

  

设置要使用的并行度   在查询中。并行度是   最大并发数   执行将用于的任务   处理查询。

从这里开始:

MSDN

答案 2 :(得分:2)

看来PLINQ会调整线程数。当我在一个while(true)循环中包装上面的代码时,前两次迭代需要两秒钟才能运行,但第三次和以上只需要一秒钟。 PLINQ了解核心是空闲的并且增加了线程数量。可观!

答案 3 :(得分:-1)

我同意Rory,除了IO。没有使用磁盘IO进行测试,但网络IO最终可能比更多线程更有效,而不是CPU上的内核。

简单测试(对于每个线程计数运行测试会更正确,因为网络速度不是常数,但仍然是)以证明:

    [Test]
    public void TestDownloadThreadsImpactToSpeed()
    {
        var sampleImages = Enumerable.Range(0, 100)
            .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.")
            .ToArray();            

        for (int i = 0; i < 8; i++)
        {
            var start = DateTime.Now;
            var threadCount = (int)Math.Pow(2, i);
            Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount},
                         index =>
                             {
                                 using (var webClient = new WebClient())
                                 {
                                     webClient.DownloadFile(sampleImages[index],
                                                            string.Format(@"c:\test\{0}", index));
                                 }
                             });

            Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds);
        }
    }

使用带有SSD的8核心机器从CDN获得500x500px图像的结果是:

  

线程数:1,秒:25.3904522
  线程数:2,秒:10.8986233
  线程数:4,秒:9.9325681
  线程数:8,秒:3.7352137
  线程数:16,秒:3.3071892
  线程数:32,秒:3.1421797
  线程数:64,秒:3.1161782
  线程数:128,秒:3.7272132

最后的结果有这样的时间我首先考虑因为我们只需下载100张图片:)

使用8-64个线程的时间差异并不大,但这是在8核心机器上。如果它是2核心机器(便宜的终端用户笔记本电脑),我认为强制使用8个线程会产生更大的影响,而不是8核心机器强制使用64个线程。