线程与单线程

时间:2010-05-25 05:35:35

标签: c# .net multithreading cpu

是否始终保证多线程应用程序的运行速度比单线程应用程序快?

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

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

掌握CPU并充分利用它的最佳做法是什么?

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

8 个答案:

答案 0 :(得分:60)

类比可能会有所帮助。

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

您所在城镇的交通信号灯是完美的交通信号灯。除非交叉路口有人,否则它们总是绿色的。

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

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

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

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

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

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

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

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

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

答案 1 :(得分:9)

我的意见

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

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

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

  

......好像是单线程版的   应用程序运行速度比   有两个线程的版本。

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

  

杰克的最佳做法是什么?   CPU并充分利用它?

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


直接来自Wikipedia

优点

一些优点包括:

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

缺点

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

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

更新

  

此外,数据库服务器在   代码运行的同一台机器。   它不是一个SQL服务器。这是一个nosql   DBMS。所以请不要假设任何事情   关于数据库服务器。

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

  

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

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

  

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

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:2)

当然不是。线程会产生开销,因此应用程序的好处取决于它是parallel的原因。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

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

enter image description here