40

我正在使用Parallel.ForEach,我正在做一些数据库更新,现在没有设置MaxDegreeOfParallelism,双核心处理器计算机导致sql客户端超时,其中四核心处理器机器在某种程度上没有超时。MaxDegreeOfParallelism有什么作用?

现在我无法控制运行代码的哪种处理器内核可用,但是有些设置可以通过MaxDegreeOfParallelism进行更改,可能会同时运行较少的操作并且不会导致超时?

我可以增加超时,但它不是一个很好的解决方案,如果在较低的CPU上,我可以同时处理较少的操作,这将减少对CPU的负载。

好吧我已经读过所有其他帖子和MSDN,但将MaxDegreeOfParallelism设置为较低的值,使我的四核心机器遭受损失?

例如,有没有办法做到这一点,如果CPU有两个核心,那么使用20,如果CPU有四个核心然后40?

回答

58

答案是,它是整个并行操作的上限,与核心数量无关。

所以,即使你不使用CPU,因为你正在等待IO或锁,没有额外的任务将并行运行,只有你指定的最大值。

为了找到答案,我写了这段测试代码。在那里有一个人造锁以刺激TPL使用更多的线程。代码等待IO或数据库时也会发生同样的情况。

class Program 
{ 
    static void Main(string[] args) 
    { 
     var locker = new Object(); 
     int count = 0; 
     Parallel.For 
      (0 
      , 1000 
      , new ParallelOptions { MaxDegreeOfParallelism = 2 } 
      , (i) => 
        { 
         Interlocked.Increment(ref count); 
         lock (locker) 
         { 
          Console.WriteLine("Number of active threads:" + count); 
          Thread.Sleep(10); 
         } 
         Interlocked.Decrement(ref count); 
        } 
      ); 
    } 
} 

如果我没有指定MaxDegreeOfParallelism,则控制台日志记录显示最多可同时运行大约8个任务。像这样:

Number of active threads:6 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:6 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 

它开始降低,随着时间的推移而增加,最终试图同时运行8次。

如果我把它限制在某些任意值(比如2),我得到

Number of active threads:2 
Number of active threads:1 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 

哦,这是一个四核机器上。

+0

我的逻辑没有任何等待或任何IO,它只是更新SQL,是的SQL可能有自己的,但大多数我正在等待SQL完成。什么是使用的活动线程的默认最大数量? – 2012-03-02 19:49:19

+0

默认值是每个核心2个,但如果您的代码不使用CPU,则TPL可以提高此值。大多数数据库涉及一定数量的IO。 – 2012-03-02 20:01:08

+1

如果我的6核机器负载很重,它只使用1或2个线程。如果其轻载,则会达到12.它的智能足以将现有的系统负载考虑在内。 – Contango 2013-08-08 14:05:21

-1

它设置线程并行运行的数...

+0

但它是否考虑到核心? – 2012-03-02 18:57:45

+0

基本上你使用的是哪种类型的db? – SolidSnake 2012-03-02 19:08:54

+0

相同的操作系统,相同的程序,相同的数据(基本复制器),但一个是双四核的高端机器,两个是简单的双核心机器,相同的程序从其他服务器获取数据并将数据存回SQL(大量斑点和图像)。 – 2012-03-02 19:18:34

1

听起来好像是你在并行运行的死锁,这意味着,除非你能找到并修复这是造成该问题的代码,你根本不应该并行化它。

+0

-1,问题不是并行或不并行,它很简单,SQL自己计算,但太多的并行请求使客户端超时,我想运行较少的操作。死锁不是一个问题,因为具有相同逻辑的四核机器,相同的SQL运行良好,我不想继续增加超时。 – 2012-03-02 18:57:27

+0

您是否尝试过增加超时时间并确认它有效?并发性问题可能非常微妙,许多事情可能会导致它们消失并看似随机地出现。事实上,它在一个拥有更多内核的不同机器上运行并不意味着它不会被破坏,或者说更多的内核是帮助的。 – jimrandomh 2012-03-03 23:36:12

+0

增加超时确实有帮助。但是在小型机器和小型机器上CPU占用率超过了50%,而在大型机器上占用了不到5%,现在我处于一个需要找出性能问题的地步,并且我可以做些什么来改变代码或者只是需要升级CPU。 – 2012-03-04 08:53:09

13

例如,有没有办法做到这一点,如果CPU有两个核心,那么使用20,如果CPU有四个核心,那么40?

你可以做到这一点,使并行依赖于CPU内核的数量:

var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 }; 
Parallel.ForEach(sourceCollection, options, sourceItem => 
{ 
    // do something 
}); 

然而,新的CPU的倾向于使用超线程技术来模拟额外的核心。所以,如果你有一个四核处理器,那么Environment.ProcessorCount可能会报告这8个核心。我发现如果你设置并行性来模拟核心,那么它实际上会减慢其他线程,比如UI线程。

因此,虽然操作速度会更快,但应用程序用户界面在此期间可能会出现明显的延迟。将Environment.ProcessorCount除以2似乎达到了相同的处理速度,同时仍然保持CPU可用于UI线程。