为啥多线程应用程序通常会扩展不好?

Posted

技术标签:

【中文标题】为啥多线程应用程序通常会扩展不好?【英文标题】:Why would multi threaded applications in general scale bad?为什么多线程应用程序通常会扩展不好? 【发布时间】:2012-04-27 08:48:57 【问题描述】:

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

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

    线程间通信不好,拖慢速度 芯片上的内核数和 CPU 的内存带宽不会按比例增加。这会导致每个核心的内存带宽越慢,芯片上的核心使用越多。

还有什么问题?

【问题讨论】:

Communication between processes... 你说的是多线程 ..可能是错字/braino。我确定 OP 的意思是“线程之间”:) 好吧,要正确,我们要么坚持进程,要么坚持线程。无论如何,因为我对理论比对实际正确性更感兴趣 - 请原谅我:) 我会添加 (3) 线程都需要访问某些共享资源(例如互斥锁或硬盘驱动器等),最终他们轮流访问它,大多数线程都被阻塞了很多时候都在等待轮到他们。 【参考方案1】:

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

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

此外,考虑到 O(1) 和 O(n) 算法之间的差异,算法的可扩展性更为基础。当然,这里的主题可能侧重于处理能力的可扩展性,而不是数据大小。

【讨论】:

【参考方案2】:

我认为,在 (1) 中,您已经确定了可能对多线程应用程序的性能产生负面影响的最重要因素之一。特别是。谷歌“虚假分享”。

(2),但是只影响一组多线程应用程序 - 那些并行运行 CPU 绑定线程的应用程序。如果一个应用程序使用了很多 I/O 绑定的线程,那么 (2) 并不重要。

看我这里的盒子,它有 100 个进程和 1403 个线程,CPU 使用率 3%。 100 个进程中只有 7 个是单线程的。因此,大多数应用程序都是多线程的,但 I/O 等待。

目前,如果它只有一个核心,我的盒子会很好地工作。当然,点击一个打开我的浏览器的链接可能会稍微慢一点来打开一个复杂的页面,但不会慢很多。

在最常见的情况下,应用程序是多线程的,以利用抢占式多任务程序的高 I/O 性能,应用程序的扩展性确实非常好,即使在单核 CPU 上也是如此。

尽量不要陷入认为抢先式多任务操作系统都是关于“并行执行 CPU 密集型任务”的陷阱——它们实际上通过强制需要锁定、同步、信号等来使这变得困难。更多的是关于高性能 I/O,这是协作调度程序非常不擅长的。

【讨论】:

谢谢!要点,当您谈论调度程序时特别有趣 我使用的最后一个协同调度的操作系统是 Win 3.1 :((( 每次我听 Florence 和 'Dog days are over' 时,我都会想到 Win 3.1,'Shake it out'-> Win 95, 'Remain Nameless'-> Win ME。Windows 框在 NT/W2K 中变得有用 - 完全优先的抢占式调度程序。【参考方案3】:

许多多线程应用程序都是围绕“一个用户一个线程”概念构建的,这意味着一旦需要处理用户或杂务,就会为任务分配一个线程。每个额外的线程都会增加调度程序的负载,直到所有处理都完成并试图确定此时应该运行哪个线程。将此称为“调度程序饱和”。

Windows(多线程引擎,而不是 95/98/Me 等)有一种称为 I/O 完成端口的机制,它建议每个处理器一个线程以获得最佳性能。基于 IOCP 的应用程序通常非常快,但与往常一样,瓶颈反而出现在其他地方,例如耗尽某些类型的操作系统内存或在通信介质上等待。

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

【讨论】:

【参考方案4】:

我会补充:

    线程越多,它们在 CPU 缓存中的份额就越小。典型的现代 CPU 可能具有 3 级缓存:L1、L2 和 L3。 L1 可能是该核心专用的,但 L2 和 L3 可能在芯片上的核心或其他东西之间共享。因此,单个线程可以使用整个 L2 和 L3,但如果您有很多线程,那么您会获得更多的缓存未命中,具体取决于您的算法配置文件。

另见:

many-core CPU's: Programming techniques to avoid disappointing scalability

【讨论】:

【参考方案5】:

它可能受到主内存的固定最大带宽的限制,您的程序已用完内存带宽,但是您使更多线程无法创建更多可用内存带宽。这与您的特定应用程序有关,无论是内存限制还是计算限制,请参阅roofline model。

【讨论】:

以上是关于为啥多线程应用程序通常会扩展不好?的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask异步操作

javajava 多线程 异步计算 FutureTask 源码详解

为啥堆栈通常会向下增长?

MFC中CDialog 的OnKeyDown()为啥不好使?

多线程程序中的fork

多线程作业队列管理器