线程与单线程

问题描述 投票:23回答:8

总是保证多线程应用程序比单线程应用程序运行得更快吗?

我有两个线程从数据源填充数据但不同的实体(例如:数据库,来自两个不同的表),似乎应用程序的单线程版本比具有两个线程的版本运行得更快。

为什么会这样?当我看一下性能监视器时,两个cpu都非常灵巧?这是由于上下文切换?

驱动CPU并充分利用它的最佳实践是什么?

我希望这不是模棱两可的。

c# .net multithreading cpu
8个回答
60
投票

类比可能会有所帮助。

你需要将一堆信件发送到城镇周围的各个地址。因此,您雇用一个带摩托车的人来发送您的信件。

您镇上的交通信号是完美的交通信号。它们总是绿色的,除非交叉路口有人。

摩托车上的那个人拉着嘴来递送一堆信件。由于路上没有其他人,每盏灯都是绿色的,这很棒。但你认为嘿,这可能会更快。我知道,我会雇用另一名司机。

麻烦是**你只有一辆摩托车*。所以现在你的第一个司机在摩托车上开车一段时间,然后不时地停下来,下车,第二个司机跑起来,跳上去,然后开车。

这更快吗?不,当然不。那个慢了。添加更多线程不会使任何更快。线程不是魔术。如果一个处理器能够每秒进行十亿次操作,那么添加另一个线程不会突然再次使另一个十亿次操作可用。相反,它从其他线程窃取资源。如果一辆摩托车可以达到每小时100英里,那么停下自行车并让另一名司机上车并不会让它变得更快!很明显,在这个方案中,字母的传递速度并不快,它们只是以不同的顺序传递。

好的,那么如果你雇用两名司机和两辆摩托车怎么办?现在你有两个处理器和每个处理器一个线程,所以它会更快,对吧?不,因为我们忘记了红绿灯。之前,只有一辆摩托车在任何时候都以高速行驶。现在有两个司机和两个摩托车,这意味着现在有时其中一个摩托车必须等待,因为另一个摩托车在交叉路口。同样,添加更多线程会减慢您的速度,因为您花费更多时间来争用锁定。你添加的处理器越多,它就越糟糕;你最终会花费越来越多的时间在红灯等待,而越来越少的时间来驱动信息。

如果这样做会导致锁争用,那么添加更多线程可能会导致负面可伸缩性。线程越多,争用越多,事情就越慢。

假设您使引擎更快 - 现在您拥有更多处理器,更多线程和更快的处理器。这总是让它更快吗?没有。它经常没有。提高处理器速度可能会使多线程程序变慢。再想想交通。

假设你有一个拥有数千名司机和64辆摩托车的城市,司机都在摩托车之间来回奔跑,交叉路口的一些摩托车挡住了其他摩托车。现在你让所有这些摩托车跑得更快。这有帮助吗?嗯,在现实生活中,当你开车的时候,你能在保时捷和本田思域的速度上跑两倍吗?当然不是;在城市驾驶的大部分时间你都被困在交通堵塞中。

如果你可以更快地开车,通常你最终会等待更长时间的交通,因为你最终会更快地进入拥堵状态。如果每个人都加快拥堵速度,那么拥堵就会变得更糟。

多线程性能可能非常违反直觉。如果你想要极高的性能我建议不要使用多线程解决方案,除非你有一个“令人尴尬的并行”的应用程序 - 也就是说,某些应用程序显然可以投掷多个处理器,如计算Mandelbrot集或进行光线跟踪或一些这样的事情。然后,不要在处理问题时抛出更多线程。但对于许多应用程序,启动更多线程会降低您的速度。


9
投票

我的看法

不,不能保证多线程应用程序比单线程应用程序运行得更快。主要问题是将工作负载正确分配给所有可用内核并最小化锁定和上下文切换。

我认为人们可以做的一些更糟糕的事情就是尝试多线程处理他们的CPU密集型任务。有时它们最终会创建数百个线程,每个线程都在尝试执行大量CPU密集型计算。在这种情况下,最好的办法是为每个核心创建一个(或两个)线程。

在涉及UI的情况下,几乎总是首选将所有CPU密集型工作委托给线程,以保持UI响应。这可能是线程最常用的用法。

...似乎应用程序的单线程版本比具有两个线程的版本运行得更快。

你有没有进行任何性能分析?如果你还没有,那么你所观察到的有点无关紧要。

驱动CPU并充分利用它的最佳实践是什么?

鉴于您的问题的描述,似乎您的性能问题不受CPU限制,但I / O绑定...您与数据库的通信比处理器缓存慢很多,如果它是一个网络数据库,那么它甚至更慢比你的硬盘。您的性能瓶颈在于数据库,因此您需要创建足够的线程来最大化与数据库的连接吞吐量。


直接来自Wikipedia

好处

一些优点包括:

  • 如果一个线程获得了大量的缓存未命中,其他线程可以继续利用未使用的计算资源,从而可以加快整体执行速度,因为如果只执行一个线程,这些资源就会空闲。
  • 如果一个线程不能使用CPU的所有计算资源(因为指令依赖于彼此的结果),运行另一个线程允许不让这些空闲。
  • 如果多个线程在同一组数据上工作,它们实际上可以共享其缓存,从而可以更好地缓存高速缓存或对其值进行同步。

缺点

对多线程的一些批评包括:

  • 当共享硬件资源(如高速缓存或转换后备缓冲区(TLB))时,多个线程可能会相互干扰。
  • 即使只执行一个线程,单线程的执行时间也不会改善,但可能会降级。这是由于较慢的频率和/或额外的流水线级,这是适应线程切换硬件所必需的。
  • 多线程的硬件支持对于软件来说更加明显,因此与多处理相比,需要对应用程序和操作系统进行更多更改。

更新

此外,数据库服务器与运行代码的计算机位于同一台计算机上。它不是一个SQL服务器。它是一个nosql dbms。所以请不要假设任何关于数据库服务器。

一些NoSQL系统是基于磁盘的,从多个线程读取磁盘几乎可以保证降低性能。当在线程之间跳转时,硬盘可能必须将磁头移动到磁盘的不同扇区,这很糟糕!

我理解你想要的是IO速度。但它仍然是同一台机器。为什么IO这么慢?

您的NoSQL系统可能是基于磁盘的,因此您的所有数据都存储在磁盘上而不是加载到内存中(如SQL Server)。考虑一下架构:磁盘是RAM的缓存,RAM缓存CPU缓存,CPU缓存是CPU寄存器。所以磁盘 - > Ram - > CPU缓存 - >寄存器,在你到达寄存器之前有3级缓存。根据您使用的数据量,您可能会在每个级别的线程中为两个线程获得大量缓存未命中... CPU缓存中的缓存未命中将从RAM加载更多数据,缓存未命中RAM将从磁盘加载更多数据,所有这些都转化为吞吐量降低。

在其他评论家“创造足够的线程来利用......”创建许多线程也需要时间。对?

不是......你只有两个主题。你创建线程的次数是多少?你多久创造一次?如果您只创建两个线程并且您在应用程序的整个生命周期中在这两个线程中完成所有工作,那么创建应该关注的线程几乎没有性能开销。


3
投票

如果您的程序I / O很重并且花费大部分时间等待I / O(如数据库操作),那么线程将无法更快地运行。

如果它在CPU中做了很多计算,那么它有没有好处,取决于你如何写它。


2
投票

当然不是。线程会带来开销,因此应用程序的好处取决于parallel是多少。


1
投票

不它不是。因为当你进行多线程时,你的CPU必须在线程,内存,寄存器和成本之间切换。有些任务可以像合并排序一样被整除,但有些任务可能无法被子任务整除,例如检查一个数字是否是素数(这只是我突然的例子),然后如果你试图将它分开out,它只是像单线程问题一样运行。


0
投票

在您拥有数百个线程之前,上下文切换开销不是问题。上下文切换的问题经常被高估(运行任务管理器并通知已经启动了多少线程)。您观察到的尖峰依赖于与本地cpu计算相比相当不稳定的网络通信。

当系统由几个(5-15)组件组成,并且每个组件都有自己的带有限线程池的消息队列时,我建议在SEDA(分阶段事件驱动架构)中编写可伸缩的应用程序。您可以调整池的大小,甚至应用更改线程池大小的算法,以使某些组件比其他组件更高效(因为所有组件共享相同的CPU)。您可以调整特定硬件的池大小,使SEDA应用程序具有极高的可调性。


0
投票

我已经看到了现实世界的例子,其中代码执行得非常糟糕,添加了更多的处理器(线程之间可怕的锁争用)系统需要移除处理器以恢复性能;所以是的,通过添加更多执行线程可以使代码工作更糟。

IO约束应用程序是另一个很好的例子,如上所述。


0
投票

根据Amdahl's law,最大加速度取决于可以并行化的算法的比例。如果算法高度并行,则增加CPU的数量并且线程将大幅增加。如果算法不是平行的(存在大量代码流控制或数据争用),则没有增益或者甚至可能发生性能降低。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.