在几个线程上运行Parallel.Foreach的性能

时间:2011-03-22 22:16:32

标签: c# .net performance parallel-processing

我有3个主要的处理线程,每个线程都通过Parallel.Foreach对ConcurrentDictionaries的值执行操作。这些词典的大小从1,000个元素到250,000个元素不等

TaskFactory factory = new TaskFactory();
Task t1 = factory.StartNew(() =>
{
        Parallel.ForEach(dict1.Values, item => ProcessItem(item));
});

Task t2 = factory.StartNew(() =>
{                                
        Parallel.ForEach(dict2.Values, item => ProcessItem(item));
});

Task t3 = factory.StartNew(() =>
{                           
        Parallel.ForEach(dict3.Values, item => ProcessItem(item));
});
t1.Wait();
t2.Wait();
t3.Wait();

我比较了这个构造的性能(总执行时间),只是在主线程中运行了Parallel.Foreach,性能提高了很多(执行时间减少了大约5倍)

我的问题是:

  1. 是否有问题 接近上面?如果是,那又怎么样 可以改进吗?
  2. 执行时间不同的原因是什么?
  3. 调试/分析这种情况的好方法是什么?
  4. 编辑:为了进一步澄清这种情况:我正在模拟WCF服务上的客户端调用,每个调用都来自一个单独的线程(任务的原因)。我还尝试使用ThreadPool.QueueUserWorkItem而不是Task,没有性能提升。字典中的对象有20到200个属性(只是小数和字符串),没有I / O活动

    我通过在BlockingCollection中排队处理请求并在当时处理它们来解决了这个问题

3 个答案:

答案 0 :(得分:7)

你可能过度并行化了。

如果您已经在每个任务中使用了良好(并且平衡)的并行化,则无需创建3个任务。

Parallel.Foreach已经尝试使用正确数量的线程来利用完整的CPU潜力而不会使其饱和。通过创建Parallel.Foreach的其他任务,你可能会让它饱和 (编辑:作为Henk said,他们在协调并行运行时生成的线程数可能会遇到一些问题,至少会导致更大的开销。

请查看here以获取一些提示。

答案 1 :(得分:3)

首先,Task不是Thread。

您的Parallel.ForEach()调用由使用ThreadPool的调度程序运行,并应尝试优化线程使用情况。 ForEach适用于分区程序。当你并行运行它们时,它们不能很好地协调。

仅在存在性能问题时,请考虑帮助执行额外任务或DegreeOfParallelism指令。然后首先进行剖析和分析。

对结果的解释很困​​难,可能是由许多因素(例如I / O)引起的,但“单一主要任务”的优点是调度程序具有更多控制权并且CPU和Cache使用得更好(局部性)。

答案 2 :(得分:2)

字典的大小和外观各不相同(鉴于所有内容都在<5s内完成),处理工作量很小。不知道更多,很难说实际上发生了什么。你的字典项有多大?您正在比较这个主线程场景看起来像这样吗?

Parallel.ForEach(dict1.Values, item => ProcessItem(item)); 
Parallel.ForEach(dict2.Values, item => ProcessItem(item)); 
Parallel.ForEach(dict3.Values, item => ProcessItem(item)); 

通过在每个ForEach周围添加任务,您需要增加更多管理任务的开销,并可能导致内存争用,因为dict1,dict2和dict3都会尝试并同时处于内存和热点缓存中。请记住,CPU周期很便宜,缓存未命中不是。