为啥 C++ 中的多线程会降低性能
Posted
技术标签:
【中文标题】为啥 C++ 中的多线程会降低性能【英文标题】:why multithreading in c++ reduces the performance [closed]为什么 C++ 中的多线程会降低性能 【发布时间】:2018-12-27 20:39:20 【问题描述】:在这段代码中,多线程正在降低性能:
unsigned long num1 = 0;
unsigned long num2 = 0;
thread myThread1(count1,&num1);
thread myThread2(count2, &num2);
myThread1.join();
myThread2.join();
cout << num1 << endl;
cout << num2 << endl;
void count1(unsigned long *num1)
long b = clock();
while( clock() - b < 1000)
(*num1)++;
void count2(unsigned long *num2)
long b = clock();
while( clock() - b < 1000)
(*num2)++;
最后 num1 = 690,000 和 num2 = 700,000(num1 和 num2 按此顺序)但是当我在单线程模式下运行时(当我评论第二个线程时)num = 1,600,000 所以多线程正在降低性能。为什么会这样?通过在 num1 和 num2(64 字节)之间添加一个填充,性能会变得更好,但仍然比单线程(num1,num2 = 750,000)更差
(当性能更好时,CPU 可以计数更多,但在第一部分它计数为 1,300,000,第二部分为 1,600,000)
(num1 和 num2 仅用于计数)
这是整个代码(已编辑)
【问题讨论】:
线程增加了一些不可忽视的开销。 您没有正确衡量“性能”,也没有正确定义它是什么。您希望您的代码做什么以及持续多长时间?用于比较的单线程代码列表在哪里。你用什么来分析它?为这两种情况提供 MCVE。我们没有精神力量来查看你在 count1 或 count2 中所做的事情 如果这是你的变量的声明,那么你有一个错误共享的坏情况(如果你正在做类似while true ++*num
的事情。)
不能肯定,但这看起来确实是false sharing 的主要候选人。
count1
和 count2
是做什么的?我会假设那些只是添加数字,但那些不会表明任何关于性能的东西。
【参考方案1】:
速度变慢的可能原因是您的 num
变量可能共享一个缓存行。
在这种情况下,当num1
由内核 1 上的线程 1 更新时,该变量也必须在内核 2 上的线程 2 上更新,这将减慢 num2
的更新速度。 num2
反之亦然。
这是考虑到您实际上是在内核上固定线程(这种情况也会减慢执行速度)。
尝试声明num1
,用64字节填充,然后num2
。
这将由适当的配置文件工具(如 VTune(现在免费))标记。这也可以正确衡量性能。
阅读您的线程代码后,您实际上只是在增加您的变量一段时间(它是std::clock()
?不是衡量性能的最佳方法,尤其是对于多线程,这就是硬件计数器的用途,而且循环似乎很小,例如,您应该测量一秒),因此您可能确实存在错误共享。在您的应用程序上运行 VTune 并检查缓存失效计数器,它应该是通过屋顶。
【讨论】:
虽然这个答案是有道理的,但直到 OP 共享一个 MCVE,我们才能真正知道。最好等到我们真正知道原因是什么。 @NathanOliver 是的,如果我们得到更新,我会密切关注更新答案的更多细节。 @MatthieuBrucher 如何在两个指针之间填充? 只需在它们之间添加 char[64] 垫。另请添加minimal reproducible example 以获得正确答案,这可能是有根据的猜测,但仍然是猜测。 线程的内容有可能小于创建和维护线程的开销。这会比共享缓存线更影响性能;但在帖子的内容发布之前我们不会知道。 :-(【参考方案2】:线程并不一定意味着更快,这意味着它们可以同时/并行发生,具体取决于架构。存在与线程相关的开销。
此外,您的编译器设置以及优化是否开启也很重要。
如果您尝试并行运行的函数很快,那么线程的开销将抵消任何好处。
【讨论】:
这不是真正的原因。真正的原因是变量的声明。 不保证线程会并行运行。操作系统可以串行调度同一处理器上的线程。以上是关于为啥 C++ 中的多线程会降低性能的主要内容,如果未能解决你的问题,请参考以下文章