我目前正在考虑多线程应用程序可能无法很好扩展的原因。
我知道并且一直在与之抗争的两个原因是:
- 线程间通信没有做好,速度变慢
- 芯片上的内核数量和 CPU 的内存带宽不会按比例增加。这会导致每个内核的内存带宽较慢,芯片上的内核使用量越多。
还有什么问题?
我目前正在考虑多线程应用程序可能无法很好扩展的原因。
我知道并且一直在与之抗争的两个原因是:
还有什么问题?
对于第 1 点),它们不一定“做得不好”,但在大多数情况下,存在进程/线程必须相互等待的关键部分,例如更新一些关键数据。Amdahl 定律很好地描述了这一点。
我想补充的另一点是任务本身的可伸缩性。如果任务(输入)不可扩展,则增加处理能力(核心/线程)无法提高整体吞吐量。例如,一个应用程序要处理数据流,但是有一个约束,不能并行处理来自同一流的数据包(由于顺序考虑),那么可扩展性将受到流数的限制。
此外,考虑到 O(1) 和 O(n) 算法之间的差异,算法的可扩展性更为基础。当然,也许这里的主题关注处理能力的可扩展性,而不是数据大小。
我认为,在 (1) 中,您已经确定了可能对多线程应用程序的性能产生负面影响的最重要因素之一。特别是。谷歌“虚假分享”。
(2),但是只影响一组多线程应用程序 - 那些并行运行 CPU 绑定线程的应用程序。如果一个应用程序使用许多受 I/O 限制的线程,则 (2) 无关紧要。
看看我这里的盒子,它有 100 个进程和 1403 个线程,CPU 使用率 3%。100 个进程中只有 7 个是单线程的。因此,大多数应用程序都是多线程的,但 I/O 等待。
目前,如果它只有一个核心,我的盒子可以很好地工作。当然,点击一个结束我的浏览器的链接可能会稍微慢一点来打开一个复杂的页面,但不会慢很多。
在最常见的情况下,应用程序是多线程的,以利用抢占式多任务程序的高 I/O 性能,应用程序的扩展性确实非常好,即使在单核 CPU 上也是如此。
尽量不要陷入认为抢占式多任务操作系统都是关于“并行执行 CPU 密集型任务”的陷阱——它们实际上通过强制需要锁定、同步、信号等来使这变得困难。它更多的是关于高性能I/O,协作调度程序非常不擅长的事情。
许多多线程应用程序都是围绕“一个用户一个线程”概念构建的,这意味着一旦需要处理用户或杂务,就会为任务分配一个线程。每个额外的线程都会增加调度程序的负载,导致所有处理都完成,试图确定此时应该运行哪个线程。将此称为“调度程序饱和”。
Windows(多线程引擎,而不是 95/98/Me 等)有一种称为 I/O 完成端口的机制,它建议每个处理器一个线程以获得最佳性能。基于 IOCP 的应用程序通常非常快,但与往常一样,瓶颈反而出现在其他地方,例如耗尽某些类型的操作系统内存或在通信介质上等待。
你可以在这里搜索 IOCP,它有自己的标签。
I would add:
See also:
many-core CPU's: Programming techniques to avoid disappointing scalability
它可能受到主内存的固定最大带宽的限制,您的程序已用完内存带宽,但是您使更多线程无法创建更多可用内存带宽。这与您的特定应用程序有关,无论是内存有界的还是计算有界的,请参阅屋顶线模型。