C ++中的多线程效率

时间:2013-05-23 23:14:31

标签: c++ multithreading stl

我正在尝试用C ++学习线程,并且只是对它有一些问题(更具体地说是<thread>

假设这个代码运行的机器有4个内核,我应该将操作分成4个线程吗?如果我要创建8个线程而不是4个线程,那么在4核心机器上运行速度会慢吗?如果处理器有超线程,如果我尝试使线程与物理内核或逻辑内核的数量相匹配怎么办?

我是否应该不担心机器拥有的核心数量,并尝试尽可能多地创建线程?

如果这些问题已经得到解答,我道歉;我一直在寻找有关<thread>线程的信息,这是在c11中引入的,因此我无法找到太多关于它的信息。

有问题的程序将运行许多独立的模拟。

如果有人对<thread>或一般的多线程有任何见解,我会很高兴听到它。

6 个答案:

答案 0 :(得分:4)

如果您在没有I / O的情况下执行纯计算 - 并且这些计算是独立的并且不依赖于在另一个线程中发生的其他计算的结果,则此类线程的最大数量应该是核心数(可能是一个或两个)如果系统还加载了其他任务,则更少)。

如果您正在进行网络I / O或类似操作,肯定会有更多线程。

如果你正在进行磁盘I / O,那么从磁盘读取的单个线程通常是最好的,因为从多个线程读取磁盘会导致磁盘上的读/写磁头移动,这会使速度变慢。

如果您使用线程来使代码更简单,那么线程数可能取决于您正在做什么。

它还取决于每个线程的“独立”程度。如果他们需要以复杂的方式共享数据,那么共享/等待其他线程/等等可能会使更多线程更慢。

正如其他人所说,尝试使您的框架灵活并测试不同的选项。最好是在多台机器上(除非您只有一种机器可以运行代码)。

答案 1 :(得分:3)

没有<threads.h>之类的东西,你的意思是<thread>,C ++ 11中引入的线程支持库。

您问题的唯一答案是“测试并看到”。您可以使代码足够灵活,以便可以通过传递N参数(其中N是所需的线程数)来运行。

如果你受CPU约束,那么答案将与IO绑定时的情况大不相同。

所以,测试一下!供您参考,this link can be helpful。如果你是认真的,那就继续get this book。多线程,并发等都是毛茸茸的主题。

答案 2 :(得分:2)

与您正在运行的计算机相比,不要考虑所需的线程数。只要您拥有以下流程,线程就是值得的:

答:有一些非常慢的操作,其余的过程不需要等待。

B:某些功能可以比其他功能运行得更快,不需要内联执行。

C:有很多非订单依赖I / O正在进行(Web服务器)。

这些只是启动线程有意义时的一些明显示例。因此,您启动的线程数更多地取决于代码中弹出的这些方案的数量,而不是您希望运行的体系结构。事实上,除非您正在运行一个真正需要优化的流程,否则您可能只需通过对您的体系结构进行基准测试,与您启动的线程数进行基准测试,从而获得额外性能的几个百分点,以及在现代计算机中,这个数字应该不会有太大变化。

让我们来看看I / O示例,因为它将是最有益的场景。我们假设某些程序需要通过网络与200个用户交互。网络I / O非常慢。比CPU慢几千倍。如果我们依次处理每个用户,我们会浪费数千个处理器周期,只是等待来自第一个用户的数据。我们难道不能一次处理多个用户的信息吗?在这种情况下,由于我们有大约200个用户,而我们所等待的数据比我们能处理的数据慢1000倍(假设我们对这些数据进行的处理量很少),我们应该启动与操作系统允许的一样多的线程。利用线程的Web服务器每秒可以为数百人提供服务,而不是那么多。

现在,让我们考虑一个I / O密集度较低的示例,其中我们说有几个函数依次执行,但是彼此独立,其中一些可能运行得更快,比如因为一个磁盘I / O ,另一个没有磁盘I / O.在这种情况下,我们的I / O仍然相当快,但我们肯定会浪费处理时间等待磁盘赶上。因此,我们可以启动一些线程,只是为了利用我们的处理能力,并最大限度地减少浪费的周期。但是,如果我们启动尽可能多的线程,操作系统允许我们可能会为分支预测器等引发内存管理问题......并且在这种情况下启动太多线程实际上是次优的并且可以减慢程序的速度。请注意,在这里,我从未提及机器有多少个核心!对于不同架构进行优化并不重要,但如果针对一种架构进行优化,则对于大多数架构而言,您可能非常接近最佳。再假设你正在处理所有合理的现代处理器。

答案 3 :(得分:1)

我认为大多数人会说除了c ++之外的其他语言(go,scala,cuda)可以更好地支持大规模线程项目。与数据并行相反的任务并行性在c ++中更好。我会说你应该创建尽可能多的线程,但如果数据并行性与你的问题更相关,可以考虑使用cuda并在以后链接到项目的其余部分。 注意:如果你看一下某种类型的系统监视器,你会注意到可能有超过8个线程在运行,我看着我的计算机,它同时运行了数百个线程所以不要过多担心开销。我选择提及其他语言的主要原因是管理c ++或c中的许多线程往往非常困难且容易出错,我没有提及它因为c ++程序运行速度较慢(除非你使用cuda它可能会赢得'吨)

答案 4 :(得分:1)

  

假设这个代码运行的机器有4个内核,我应该将操作分成4个线程吗?

如果您的代码的某些部分可以并行运行,那么可以使其更快,但这是非常棘手的,因为加载线程并在它们之间切换数据需要花费大量时间。

  

如果我要创建8个线程而不是4个线程,这会在4核心机器上运行得更慢吗?

这取决于它必须做的上下文切换。有时执行会经常在线程之间切换,有时它不会,但这很难控制。在任何情况下,它都不会比执行相同工作的4个线程运行得快。

  

如果处理器有超线程,如果我尝试使线程与物理内核或逻辑内核的数量相匹配怎么办?

超线程与拥有更多内核几乎相同。当您注意到真实核心和执行核心之间的差异时,您将有足够的知识来解决这些警告。

  

我是否应该不担心机器拥有的核心数量,并尝试尽可能多地创建线程?

不,线程难以管理,尽可能避免使用它们。

  

有问题的程序将运行许多独立的模拟。

你应该研究openmp。它是C中的一个库,用于在程序可以拆分时并行化计算。不要将并行与并发混淆。并发只是多个线程协同工作,而并行是专门为加速您的应用程序。也许openmp对你的东西来说太过分了,但是知道你何时接近并行计算是一件好事

答案 5 :(得分:0)

关于超线程,让我评论一下我从经验中发现的内容。

在大密集矩阵乘法中,超线程实际上会提供更差的性能。例如,Eigen和MKL都使用OpenMP(至少我使用它们的方式)并且在我的系统上获得更好的结果,该系统具有四个核心和超线程,仅使用四个线程而不是八个线程。另外,在我自己的GEMM代码中,性能比Eigen更好,使用四个线程而不是八个线程也能获得更好的结果。

然而,在我的Mandelbrot绘图代码中,我使用OpenMP的超线程(八个线程而不是四个线程)获得了巨大的性能提升。总体趋势(到目前为止)似乎是如果代码在OpenMP中使用schedule(static)运行良好,那么超线程无效甚至可能更糟。如果代码使用schedule(dynamic)更好地工作,那么超线程可能有所帮助。

换句话说,到目前为止,我的观察结果是,如果每个线程的运行时间可以变化很多,那么超线程可以提供帮助。如果每个线程的运行时间是恒定的,那么它甚至可能使性能变差。但是你必须测试并查看每个案例。