为什么多线程应用程序在一般情况下会很糟糕



我目前正在考虑多线程应用程序可能无法很好地扩展的原因。

我知道并且我一直在与之抗争的两个原因是:

  1. 线程之间的通信做得不好,速度变慢
  2. 芯片上的内核数和 CPU 的内存带宽不会成比例地增加。这导致每个内核的内存带宽越慢,芯片上使用的内核就越多。

还有什么问题?

对于第 1 点(,它们不一定"做得不好",但在大多数情况下,进程/线程必须相互等待关键部分,例如更新一些关键数据。阿姆达尔定律很好地描述了这一点。

我想补充的另一点是任务本身的可扩展性。如果任务(输入(不可缩放,则增加处理能力(内核/线程(无法提高整个吞吐量。例如,一个应用程序是处理数据流的,但存在一个约束,即来自同一流的数据包不能并行处理(由于排序考虑(,那么可扩展性将受到流数量的限制。

此外,考虑到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 的应用程序通常非常快,但与往常一样,瓶颈出现在其他地方,例如耗尽某些类型的操作系统内存或等待通信介质。

您可以在SO这里搜索IOCP,它有自己的标签。

我会补充:

  1. 线程越多,它们在 CPU 缓存中的份额就越小。 典型的现代 CPU 可能有 3 个级别的缓存:L1、L2 和 L3。 L1 可能是该内核专用的,但 L2 和 L3 可能在芯片或其他内核之间共享。因此,单个线程可以使用整个L2和L3,但是如果您有很多线程,则根据算法的配置文件,您将获得更多的缓存未命中。

另请参阅:

众核CPU:避免令人失望的可扩展性的编程技术

它可能受到主内存的固定最大带宽的限制,其中程序已用完内存带宽,但是您创建更多线程无法创建更多可用内存带宽。这与您的特定应用程序相关,无论是内存绑定的应用程序还是计算绑定的应用程序,请参阅屋顶线模型。

最新更新