总是保证多线程应用程序比单线程应用程序运行得更快吗?
我有两个线程从数据源填充数据但不同的实体(例如:数据库,来自两个不同的表),似乎应用程序的单线程版本比具有两个线程的版本运行得更快.
为什么会这样?当我看一下性能监视器时,两个cpu都非常灵巧?这是由于上下文切换?
驱动CPU并充分利用它的最佳实践是什么?
我希望这不是模棱两可的.
类比可能会有所帮助.
你需要将一堆信件发送到城镇周围的各个地址.因此,您雇用一个带摩托车的人来发送您的信件.
您镇上的交通信号是完美的交通信号.它们总是绿色的,除非交叉路口有人.
摩托车上的那个家伙拉着一堆字母拉链.由于路上没有其他人,每盏灯都是绿色的,这很棒.但你认为嘿,这可能会更快.我知道,我会雇用另一名司机.
麻烦是**你只有一辆摩托车*.所以现在你的第一个司机在摩托车上开了一段时间,然后不时地停下来,下车,第二个司机跑起来,跳上去,然后开车.
这更快吗?不,当然不.那个慢了.添加更多线程不会使任何更快.线程不是魔术.如果一个处理器能够每秒进行十亿次操作,那么添加另一个线程不会突然再次使另一个十亿次操作可用.相反,它从其他线程窃取资源.如果一辆摩托车可以达到每小时100英里,那么停下自行车并让另一名司机上车并不会让它变得更快!很明显,在这个方案中,字母的传递速度并不快,它们只是以不同的顺序传递.
好的,那么如果你雇用两名司机和两辆摩托车怎么办?现在你有两个处理器和每个处理器一个线程,所以它会更快,对吧?不,因为我们忘记了红绿灯.之前,只有一辆摩托车在任何时候都以高速行驶.现在有两个司机和两个摩托车,这意味着现在有时其中一个摩托车必须等待,因为另一个摩托车在交叉路口.同样,添加更多线程会减慢您的速度,因为您花费更多时间来争用锁定.你添加的处理器越多,它就越糟糕; 你最终会花费越来越多的时间在红灯等待,而越来越少的时间来驱动信息.
如果这样做会导致锁争用,那么添加更多线程可能会导致负面可伸缩性.线程越多,争用越多,事情就越慢.
假设您使引擎更快 - 现在您拥有更多处理器,更多线程和更快的处理器.这总是让它更快吗?没有.它经常没有.提高处理器速度可能会使多线程程序变慢.再想想交通.
假设你有一个拥有数千名司机和64辆摩托车的城市,司机都在摩托车之间来回奔跑,交叉路口的一些摩托车挡住了其他摩托车.现在你让所有这些摩托车跑得更快.这有帮助吗?嗯,在现实生活中,当你开车的时候,你能在保时捷和本田思域的速度上跑两倍吗?当然不是; 在城市驾驶的大部分时间你都被困在交通堵塞中.
如果你可以更快地开车,通常你最终会等待更长时间的交通,因为你最终会更快地进入拥堵状态.如果每个人都加快拥堵速度,那么拥堵就会变得更糟.
多线程性能可能非常违反直觉.如果你想要极高的性能我建议不要使用多线程解决方案,除非你有一个"令人尴尬的并行"的应用程序 - 也就是说,某些应用程序显然可以投掷多个处理器,如计算Mandelbrot集或进行光线跟踪或一些这样的事情.然后,不要在处理问题时抛出更多线程.但对于许多应用程序,启动更多线程会降低您的速度.
不,不能保证多线程应用程序比单线程应用程序运行得更快.主要问题是将工作负载正确分配给所有可用内核并最小化锁定和上下文切换.
我觉得一些糟糕的事情,人们所能做的就是去尝试多线程的每一个自己的CPU密集型任务点点.有时它们最终会创建数百个线程,并且每个线程都在尝试执行大量CPU密集型计算.在这种情况下做的最好的事情就是创建一个(或可能每核双)线程.
在涉及UI的情况下,几乎总是首选将所有CPU密集型工作委托给线程,以保持UI响应.这可能是线程最常用的用法.
...似乎应用程序的单线程版本比具有两个线程的版本运行得更快.
你有没有进行任何性能分析?如果你还没有,那么你所观察到的有点无关紧要.
驱动CPU并充分利用它的最佳实践是什么?
鉴于您的问题的描述,似乎您的性能问题不受CPU限制,但I/O绑定...您与数据库的通信比处理器缓存慢很多,如果它是一个网络数据库,那么它甚至更慢比你的硬盘.您的性能瓶颈在于数据库,因此您需要创建足够的线程来最大化与数据库的连接吞吐量.
直接来自维基百科:
一些优点包括:
如果线程获得大量缓存未命中,则其他线程可以继续,利用未使用的计算资源,从而可以导致更快的整体执行,因为如果只执行单个线程,这些资源将处于空闲状态.
如果一个线程不能使用CPU的所有计算资源(因为指令依赖于彼此的结果),运行另一个线程允许不让这些空闲.
如果多个线程在同一组数据上工作,它们实际上可以共享其缓存,从而可以更好地缓存高速缓存或对其值进行同步.
对多线程的一些批评包括:
当共享硬件资源(如高速缓存或转换后备缓冲区(TLB))时,多个线程可能会相互干扰.
即使只执行一个线程,单线程的执行时间也不会改善,但可能会降低.这是由于较慢的频率和/或额外的流水线级,这是适应线程切换硬件所必需的.
多线程的硬件支持对于软件来说更加明显,因此与多处理相比,需要对应用程序和操作系统进行更多更改.
此外,数据库服务器与运行代码的计算机位于同一台计算机上.它不是一个SQL服务器.它是一个nosql dbms.所以请不要假设任何关于数据库服务器.
一些NoSQL系统是基于磁盘的,从多个线程读取磁盘几乎可以保证降低性能.当在线程之间跳转时,硬盘可能必须将磁头移动到磁盘的不同扇区,这很糟糕!
我理解你想要的是IO速度.但它仍然是同一台机器.为什么IO这么慢?
您的NoSQL系统可能是基于磁盘的,因此您的所有数据都存储在磁盘上而不是加载到内存中(如SQL Server).考虑一下架构:磁盘是RAM的缓存,RAM缓存CPU缓存,CPU缓存是CPU寄存器.所以磁盘 - > Ram - > CPU缓存 - >寄存器,在你到达寄存器之前有3级缓存.根据您使用的数据量,您可能会在每个级别的线程中为两个线程获得大量缓存未命中... CPU缓存中的缓存未命中将从RAM加载更多数据,缓存未命中RAM将从磁盘加载更多数据,所有这些都转化为吞吐量降低.
在其他评论家"创造足够的线程来利用......"创建许多线程也需要时间.对?
不是......你只有两个主题.你创建线程的次数是多少?你多久创造一次?如果您只创建两个线程并且您在应用程序的整个生命周期中在这两个线程中完成所有工作,那么创建应该关注的线程几乎没有性能开销.