C++ 我所期望的多线程的“真实世界”性能改进是什么?

C++ 我所期望的多线程的“真实世界”性能改进是什么?,c++,multithreading,performance,C++,Multithreading,Performance,我正在编写一个带有多个分支的递归树搜索程序,效果很好。为了加快速度,我正在实现一个简单的多线程:我将搜索分布到主分支中,并将它们分散到线程中。每个线程不必与其他线程交互,当找到解时,我使用互斥体将其添加到公共std::vector中,方法如下: if (CubeTest.IsSolved()) { // Solve algorithm found std::lock_guard<std::mutex> guard(SearchMutex); // Thread safe co

我正在编写一个带有多个分支的递归树搜索程序,效果很好。为了加快速度,我正在实现一个简单的多线程:我将搜索分布到主分支中,并将它们分散到线程中。每个线程不必与其他线程交互,当找到解时,我使用互斥体将其添加到公共std::vector中,方法如下:

if (CubeTest.IsSolved())
{ // Solve algorithm found
    std::lock_guard<std::mutex> guard(SearchMutex); // Thread safe code
    Solves.push_back(Alg);  // Add the solve
}
我不使用new和delete在动态存储堆中分配变量,因为内存需求很小。 我使用的最大线程数是从std::thread::hardware\u concurrency获得的数量

我做了一些测试,总是相同的搜索,但改变了使用的数量或线程,我发现了一些我没有预料到的东西。 我知道如果你把线程数量增加一倍,如果处理器有足够的容量,你就不能期望性能增加一倍,因为上下文切换之类的事情

例如,我有一个旧的Intel Xeon X5650,具有6核/12线程。如果我执行我的代码,直到第六个线程的事情是预期的,但如果我使用一个额外的线程的性能是最差的。使用更多的线程几乎不会增加性能,以至于使用所有可用的线程12几乎无法补偿仅使用6:

Xeon X5650的线程与处理时间图表:

我重复了几次测试,并显示了所有测试的平均次数

我在另一台采用Intel i7-4600U 2核/4线程的计算机上重复了这些测试,发现:

i7-4600U的线程与处理时间图表:

我知道,使用更少的内核,使用更多线程的性能增益是最差的

我还认为,当您开始在同一个核心中使用第二个线程时,性能在某种程度上会受到影响。我说得对吗?在这种情况下,我如何提高性能


所以我的问题是,如果多线程的性能提升是我在现实世界中所能期望的,或者从另一方面来说,这些数字告诉我我做错了,我应该学习更多关于多线程编程的知识。

一个使用超线程的CPU声称能够在一个内核上同时执行两个线程。但事实并非如此。它只是假装能做到这一点。在内部,它执行抢占式多任务处理:执行一位线程a,然后切换到线程B,执行一位线程B,返回到a,依此类推

那么超读有什么意义呢

CPU内的线程开关比操作系统的线程调度程序管理的线程开关快。因此,性能的提高主要是通过避免线程切换的开销来实现的。但它不允许CPU核心执行比以前更多的操作

结论:您可以从并发性中获得的性能增益取决于CPU的物理核数,而不是逻辑核数


还要记住,线程同步方法(如互斥)可能会变得非常昂贵。因此,锁定越少越好。当多个线程填充同一个结果集时,有时最好让每个线程构建自己的结果集,然后在所有线程完成后合并这些结果集。

使用超线程的CPU声称能够在一个内核上同时执行两个线程。但事实并非如此。它只是假装能做到这一点。在内部,它执行抢占式多任务处理:执行一位线程a,然后切换到线程B,执行一位线程B,返回到a,依此类推

那么超读有什么意义呢

CPU内的线程开关比操作系统的线程调度程序管理的线程开关快。因此,性能的提高主要是通过避免线程切换的开销来实现的。但它不允许CPU核心执行比以前更多的操作

结论:您可以从并发性中获得的性能增益取决于CPU的物理核数,而不是逻辑核数

还要记住,线程同步方法(如互斥)可能会变得非常昂贵。因此,锁定越少越好。当有多个线程填充同一个结果集时,有时最好让每个线程构建自己的结果集,然后在所有线程完成后合并这些结果集

我所期望的多线程的“真实世界”性能改进是什么

这取决于许多因素。一般来说,最乐观的改进是运行时减少了cores1的数量。在大多数情况下,这是无法实现的,因为线程之间需要同步

在最坏的情况下,不仅由于缺乏并行性而没有改进,而且同步开销以及缓存争用也会使运行时比t更糟糕 他使用单线程程序

峰值内存使用通常会随着线程数的增加而线性增加,因为每个线程都需要对自己的数据进行操作

由于在同步上花费了额外的时间,CPU总时间使用量和能源使用量也会增加。这与使用电池供电的系统以及适用于手机和笔记本电脑的热管理较差的系统有关

由于处理线程的额外代码,二进制大小会稍微大一些

1您是否能从逻辑内核(即超线程或群集多线程)中获得所有性能还取决于许多因素。通常,一个线程在所有线程中执行相同的函数,在这种情况下,它们倾向于使用CPU的相同部分,在这种情况下,与多个线程共享内核并不一定会带来好处

我所期望的多线程的“真实世界”性能改进是什么

这取决于许多因素。一般来说,最乐观的改进是运行时减少了cores1的数量。在大多数情况下,这是无法实现的,因为线程之间需要同步

在最坏的情况下,不仅由于缺乏并行性而没有改进,而且同步开销以及缓存争用也会使运行时比单线程程序更糟糕

峰值内存使用通常会随着线程数的增加而线性增加,因为每个线程都需要对自己的数据进行操作

由于在同步上花费了额外的时间,CPU总时间使用量和能源使用量也会增加。这与使用电池供电的系统以及适用于手机和笔记本电脑的热管理较差的系统有关

由于处理线程的额外代码,二进制大小会稍微大一些


1您是否能从逻辑内核(即超线程或群集多线程)中获得所有性能还取决于许多因素。通常,一个线程在所有线程中执行相同的函数,在这种情况下,它们倾向于使用CPU的相同部分,在这种情况下,与多个线程共享内核并不一定会带来好处。

问题应该是自包含的。请在问题中包含所有相关信息。您的代码可能出错导致此问题。例如,当您有7条螺纹时,不得将工件切割成7个大小相等的工件,并将每个工件分配给一条螺纹。这显然是行不通的,因为并非所有线程都以相同的速度运行,您只是在测量最慢线程的性能。你必须让所有7个线程一直处于繁忙状态。我将搜索树划分为几个小分支,因此我的代码是平衡的,cpu在结束前处于相同的占用率水平。问题应该是自包含的。请在问题中包含所有相关信息。您的代码可能出错导致此问题。例如,当您有7条螺纹时,不得将工件切割成7个大小相等的工件,并将每个工件分配给一条螺纹。这显然是行不通的,因为并非所有线程都以相同的速度运行,您只是在测量最慢线程的性能。你必须让所有7个线程一直处于繁忙状态。我将搜索树划分为几个小分支,因此我的代码是平衡的,cpu在结束前的占用率是相同的。好吧,如果它们是不同的事情,它可以允许cpu一次做更多的事情。例如,CPU能够同时进行浮点运算和整数运算,许多程序大多使用其中一种,因此超线程允许这些程序在一个内核上以最大速度的75%运行。Philipp,如果我理解得很好,我必须假设,使用6个线程或12个线程时,耗电热量将是相同的,但我认为我的计算机风扇使用12个线程时听起来更像。@GRVigo你是在开发软件还是空间加热器?@Phillip:我的观点不是在浪费能源,我想知道我是否可以用6个线程和更少的浪费能量得到同样的结果。超线程比这个答案所暗示的要复杂得多,而且给出的解释实际上是错误的,被否决了。好吧,如果它们是不同的事情,它可以允许CPU同时做更多的事情。例如,CPU能够同时进行浮点运算和整数运算,许多程序大多使用其中一种,因此超线程允许这些程序在一个内核上以最大速度的75%运行。Philipp,如果我理解得很好,我必须假设,使用6个线程或12个线程时,耗电热量将是相同的,但我认为我的计算机风扇使用12个线程时听起来更像。@GRVigo你是在开发软件还是空间加热器?@Phillip:我的观点不是在浪费能源,我想知道我是否能用6个线程获得同样的结果,并减少浪费的能量 这比这个答案所暗示的要复杂得多,而且给出的解释事实上是错误的,被否决了。