为什么使用更多的线程比使用更少的线程慢


29

试图使用8个线程运行程序X,并且在n分钟内结束
尝试使用50个线程运行同一程序,并且在n * 10分钟内结束

为什么会发生这种情况,如何获得可以使用的最佳线程数?

Answers:


33

这是一个复杂的问题。如果不了解线程的本质,很难说。诊断系统性能时应考虑的一些事项:

是进程/线程

  • CPU限制(需要大量的CPU资源)
  • 内存限制(需要大量RAM资源)
  • 绑定了I / O(网络和/或硬盘资源)

这三种资源都是有限的,任何一种资源都可能限制系统的性能。您需要查看您的特定情况正在消耗哪种(可能是2或3)。

您可以使用ntopiostat,并vmstat诊断正在发生的事情。


8
硬件也很重要。物理的,虚拟的,核的数量,类型芯的,L1 / L2 / L3高速缓存等
EightBitTony

45

“为什么会这样?” 很容易回答。假设您有一个走廊,可以同时容纳四个人。您想将所有垃圾一端移动到另一端。最有效率的人数是4。

如果您有1-3个人,那么您会错过使用一些走廊空间的机会。如果您有5个或更多的人,那么这些人中至少有一个基本上总是一直排在另一个人后面。增加越来越多的人只会阻塞走廊,但不会加快活动速度。

因此,您希望拥有尽可能多的人员而不会造成任何排队。 为什么要排队(或出现瓶颈)取决于slm答案中的问题。


1
您的示例具有误导性。最好这样说:“您有一个走廊,可以并排容纳四个人,并且您其他人可以使用它来完成不同的任务。有一个裁判来决定谁可以穿过走廊那么,最有效的人数是大于4且小于某个人数,此时您的人员开始排队[高度依赖上下文]。” 一般具有一些线程以上的CPU执行的数量比使用更好正好 4个线程。如果您是唯一使用CPU的人,那4是最好的数字。
Bakuriu

7
很好的例子,+ 1。Bakuriu,其示例说明了共享资源有限的问题。它是在解释问题,而不是在寻找最佳线程数。
Bananguin

1
记住线程仍然具有自己的上下文切换类型,这也很有用。如您所指出的那样,增加线程数量并不会增加性能,但是通过给内核更多的工作来做,也会浪费CPU时间。基本上,线程的收益递减,而执行过多则会导致性能下降。
布莱奇利2013年

9
每个问题都可以在许多复杂程度上进行描述。我提供了该问题的一个近似值,我认为这对解释基本原理很有用。当然,它可以更完善,更详细,但是制作的越详细,它作为问题简介的作用就越小。
AugustBitTony13年

我只想补充一点,而不是花费大量时间来计算最佳线程数,只需对其进行编码即可轻松更改。如此大的合并将需要大量的测试运行(大多数只包含数据的一小部分)才能完美。增加线程数,直到看到性能大幅下降或对其他系统活动的影响是不可接受的。
DocSalvager 2013年

20

常见的建议是n + 1个线程,n是可用的CPU内核数。这样,n个线程可以在1个线程等待磁盘I / O时使CPU工作。线程较少将无法充分利用CPU资源(在某些时候总是会有I / O等待),线程过多将导致线程争用CPU资源。

线程不是免费的,而是有上下文切换之类的开销,并且-如果必须在线程之间交换数据(通常是这种情况)-各种锁定机制。仅当您实际上有更多专用的CPU内核在其上运行代码时,这才是值得的。在单个核心CPU上,单个进程(没有单独的线程)通常比完成的任何线程处理都要快。线程并不能神奇地使您的CPU更快地运行,而只是意味着额外的工作。


给定有问题的信息量,这应该是一般的答案。我们不需要像其他答案一样全面的论文和哲学
Allahjane

8

正如其他人指出(SLM答案EightBitTony答案),这是一个复杂的问题,更是这样,因为你没有描述什么你做thred和怎么他们这样做。

但是,明确地抛出更多线程会使情况变得更糟。

在并行计算领域中,存在适用的阿姆达尔定律(或不能,但是不能描述问题的详细信息,所以……),并且可以提供有关此类问题的一般见解。

阿姆达尔定律的重点是,在任何程序(以任何算法)中,总有一个百分比不能并行运行(顺序部分),而还有另一个百分比可以并行运行(并行部分)[显然这两个部分的总和为100%。

这部分可以表示为执行时间的百分比。例如,严格顺序操作可能会花费25%的时间,其余75​​%的时间会花费在可以并行执行的操作中。

图片来自维基百科 (图片来自维基百科

阿姆达尔定律预测,对于程序的每个给定并行部分(例如75%),即使您使用越来越多的处理器来完成工作,您也只能加快执行速度(例如最多4倍)。

根据经验,在并行执行中无法转换的程序越多,使用更多执行单元(处理器)所获得的程序就越少。

考虑到您正在使用线程(而不是物理处理器),情况可能会比这更糟。请记住,可以处理线程(取决于实现和可用的硬件,例如CPU /核)共享同一物理处理器/核(这是多任务处理的一种形式,如另一个答案所示)。

这种理论上的预测(大约CPU时间)并未将其他实际瓶颈视为

  1. 有限的I / O速度(硬盘和网络“速度”)
  2. 内存大小限制
  3. 其他

在实际应用中很容易成为限制因素。


必须选择答案。
Eonil '18 -10-25

6

罪魁祸首应该是“上下文切换”。这是保存当前线程的状态以开始执行另一个线程的过程。如果多个线程具有相同的优先级,则需要切换它们直到执行完成。

在您的情况下,当有50个线程时,与仅运行10个线程相比,发生了许多上下文切换。

由于上下文切换而引入的这种时间开销使程序运行缓慢


由于我们不知道线程是什么,因此这似乎是一个猜测。是的,上下文切换会增加开销,但是如果线程正在执行某种数据分析,则问题可能出在缓存问题上(即无法使用缓存,因为每次切换线程时都必须刷​​新它)。
AugustBitTony

除非我们要处理大量上下文切换,否则线程上下文切换本身不会对性能产生数量级的影响。50个线程是高线程,但不是极端线程(现在在我的盒子中,报告225个进程,而绝不是很重)。我倾向于@EightBitTony的猜测;缓存失效可能是一个更大的问题,因为每次刷新缓存时,CPU必须等待eon来等待RAM中的代码和数据。ps ax | wc -l
CVn

2

要修复AugustBitTony的隐喻:

“为什么会这样?” 很容易回答。想象一下,您有两个游泳池,一个游泳池满了,一个空了。您想要将所有水从一个转移到另一个,并有4个桶。最有效率的人数是4。

如果你有1-3个人,那你就错过了使用一些水桶的机会。如果您有5个或更多的人,则其中至少有一个人被困在等待一个桶中。增加越来越多的人...并不能加快活动速度。

因此,您希望有尽可能多的人可以同时完成一些工作(使用存储桶)

这里的人是一个线程,而存储桶则代表执行资源是瓶颈。如果无法执行任何操作,则添加更多线程无济于事。另外,我们应该强调,将水桶从一个人传递到另一个人通常比仅一个人将水桶以相同的距离搬运要慢。也就是说,在一个核心上轮流运行的两个线程通常完成的工作量少于运行两倍的单个线程:这是因为在两个线程之间进行切换需要额外的工作。

出于您的目的,限制执行资源(存储桶)是CPU,内核还是超线程指令管道,取决于体系结构的哪一部分是您的限制因素。还要注意,我们假设线程是完全独立的。这只是如果他们共享的情况下没有数据(并避免任何碰撞缓存)。

就像有人建议的那样,对于I / O来说,限制资源可能是有用的可排队I / O操作的数量:这可能取决于整个硬件和内核因素,但可能远远大于硬件和内核因素的数量。核心。在这里,与执行绑定代码相比成本很高的上下文切换与I / O绑定代码相比非常便宜。可悲的是,我认为如果我用桶来证明这一隐喻是完全无法控制的。

请注意,使用I / O绑定代码的最佳行为通常仍然每个管道/核心/ CPU最多具有一个线程。但是,您必须编写异步或同步/非阻塞I / O代码,而相对较小的性能改进并不总是证明额外的复杂性。


PS。我对原始走廊隐喻的问题是,它强烈建议您应该能够容纳4人,其中2人携带垃圾,2人返回以收集更多的东西。然后,您可以使每个队列几乎与走廊一样长,并且添加人员确实可以加快算法的速度(您基本上将整个走廊变成了一条传送带)。

实际上,这种情况与TCP网络中延迟和窗口大小之间关系的标准描述非常相似,这就是为什么它突然出现在我眼前。


这不是一个比喻,而是一种近似的设计,旨在以人们可以轻松可视化的方式向人们解释该系统。因此,知道下一个细节级别的人们总是会“翻新”它,但是却没有意识到他们的细节级别对于初学者实际上并不是必需的。没有人从博士学位开始学习粒子物理学。之前的所有内容都是近似的,它们会逐步将您引导至其中,并随您进行精炼。这不是“错”,它不是全部。
AugustBitTony13年

没有人会混淆您使用哪种措辞,这并不是一个坏的类比。每个类比都有一定的局限性,超出了其应有的描述范围并不再有用。我之所以仅提及这一点,是因为原始版本强烈地使我想起了另一种情况,并且因为(希望)改进了预测能力,所以我认为此版本不会再变得复杂。
无用的

0

这非常简单明了。CPU所支持的线程多于实际正在串行化而不是并行化。您拥有的线程越多,系统运行速度就越慢。您的结果实际上证明了这种现象。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.