3

我正在尝试学习 C++ 中的线程,并且对此有一些疑问(更具体地说<thread>,.

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

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

如果这些问题已经得到解答,我深表歉意;我一直在寻找有关<thread>c11 中引入的 threading with 的信息,所以我找不到太多关于它的信息。

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

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

4

6 回答 6

6

如果您正在执行没有 I/O 的纯计算 - 并且这些计算是独立的并且不依赖于另一个线程中发生的其他计算的结果,那么此类线程的最大数量应该是内核数(如果系统还加载了其他任务)。

如果您正在执行网络 I/O 或类似操作,当然可以使用更多线程。

如果你在做磁盘 I/O,从磁盘读取的单线程通常是最好的,因为从多个线程读取磁盘会导致磁盘上的读/写头移动,这只会让事情变慢。

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

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

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

于 2013-05-23T23:28:11.203 回答
3

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

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

如果您受 CPU 限制,那么答案将与受 IO 限制的情况大不相同。

所以,测试看看!供您参考,此链接可能会有所帮助。如果你是认真的,那就去买这本书吧。多线程、并发等是棘手的话题。

于 2013-05-23T23:22:14.390 回答
2

与您正在运行的机器相比,不要考虑您需要的线程数。任何时候你有一个进程,线程都是有价值的:

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

B:某些函数可以比另一个运行得更快,不需要内联执行。

C: 有很多不依赖于顺序的 I/O 正在进行(Web 服务器)。

这些只是启动线程有意义时的几个明显示例。因此,您启动的线程数更多地取决于代码中弹出的这些场景的数量,而不是您期望运行的架构。事实上,除非您正在运行一个真正需要优化的进程,否则您很可能只能通过与您启动的线程数相比对您的架构进行基准测试来获得几个百分点的额外性能,并且在现代计算机中,这个数字根本不应该有太大变化。

让我们以 I/O 为例,因为它是最受益的场景。假设某个程序需要通过网络与 200 个用户交互。网络 I/O 非常非常慢。比 CPU 慢几千倍。如果我们轮流处理每个用户,我们将浪费数千个处理器周期来等待来自第一个用户的数据。难道我们不能一次处理来自多个用户的信息吗?在这种情况下,由于我们大约有 200 个用户,并且我们知道我们正在等待的数据比我们可以处理的要慢 1000 倍(假设我们对这些数据进行的处理量最少),我们应该启动操作系统允许的尽可能多的线程。

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

于 2013-05-23T23:25:19.137 回答
2

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

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

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

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

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

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

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

不,线程很难管理,尽可能避免它们。

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

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

于 2013-05-23T23:26:38.597 回答
1

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

于 2013-05-23T23:19:12.860 回答
0

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

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

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

换句话说,到目前为止,我的观察是,如果每个线程的运行时间可以变化很大,超线程可以提供帮助。如果每个线程的运行时间是恒定的,那么它甚至可能会使性能变差。但是您必须针对每种情况进行测试并查看。

于 2013-05-24T14:15:40.373 回答