我有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倍)
我的问题是:
编辑:为了进一步澄清这种情况:我正在模拟WCF服务上的客户端调用,每个调用都来自一个单独的线程(任务的原因)。我还尝试使用ThreadPool.QueueUserWorkItem而不是Task,没有性能提升。字典中的对象有20到200个属性(只是小数和字符串),没有I / O活动
我通过在BlockingCollection中排队处理请求并在当时处理它们来解决了这个问题
答案 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周期很便宜,缓存未命中不是。