多线程与顺序处理的效果如何?

Ang*_*ker 2 .net c# multithreading

我在.NET 4.51,C#Web服务上有一个工作单元,需要100毫秒.通常,Web请求包含10个单位的工作.因此,通过for循环顺序处理它需要大约一秒钟.

foreach (var u in unitsOfWork) {
  Run(u);
}
Run Code Online (Sandbox Code Playgroud)

由于该盒子有12个CPU,我决定将工作拆分并同时运行,希望获得性能提升.我Parallel.ForEach以前做的工作:

Parallel.ForEach(unitsOfWork,u => {
    Run(u);
});    
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,每个工作单元平均花费425毫秒.所以最后我节省了约500毫秒的请求.看起来我应该能够获得更好的性能,看看这个盒子有12个CPU ......我错过了一些简单的东西吗?

我寻找任何共享的东西(可能会把它拿起来),但什么都没找到......所以我试着试验.我发出了2个工作单元的请求,每个工作大约需要125毫秒.有3个请求,每个单元需要150毫秒,依此类推.随后每个单位的数量,罚款约25至30毫秒.

所以要么我做错了什么......或者多线程只有固有的开销(没有意识到它是如此之大).

PS我也尝试用Thread.Join替换Parallel.For - 结果相同.

das*_*ght 6

你可以达到的理论加速阿姆达尔定律决定:

阿姆达尔定律

T(1)单线程速度在哪里,n是CPU的数量,B不能完成的任务的百分比序列化.通过该公式,启动新任务的开销被认为是零.

如果您的任务完全可并行化,B则为零,并且您将在1/12的时间内完成任务.但是,即便是谦虚B的20%,也会将12个CPU的最高潜在加速限制为仅3.75倍 - 略高于理论极限12倍的三分之一.

无法并行化的事情包括对共享资源的序列化访问,例如I/O以及等待其他任务的完成.

处理高速缓存争用会使事情变得更糟:当并发任务访问不同的内存区域时,它们会将硬件高速缓存中的相互数据踢出,这相当于B上面公式中的增加.

总而言之,您的观察并不罕见,并且您没有遗漏任何东西.实现理论上可能的sppedup非常困难,实现的实际加速取决于并行程序需要运行的任务.