多线程比单线程慢

时间:2021-05-04 14:13:46

标签: c++ multithreading performance

已解决 - clock 显示时间不正确。 std::chrono::high_resolution_clock 显示多场增加速度约为 100%。第三个威胁将速度提高到约 130%。

--原始消息--

我编写了一个程序,可以实时对大型数组进行大量计算。可以将任务拆分为多个子数组以进行多线程处理。但是,我无法使用线程更快地运行它。

这是为演示而创建的示例虚拟代码(相同问题)。 两个线程版本最终持续 39 秒,如果它们一个接一个地计算(!),这会多几秒。数组是否是全局的等等都没有关系。我也只使用“线程构造函数”进行了一次测试,但结果相同。

我正在使用 XCode (5.1.1) 和 Macbook Air(2013 型号,Core i5,Os X 10.8.5)。是的,这是旧电脑,我很少编程...

那么,你能发现我在代码中的逻辑有什么错误吗,还是在 Xcode 等设置的某个地方?

#include <ctime>
#include <iostream>
#include <thread>

class Value
{
public:
    float a[3000000];
};

void cycle(Value *val)
{
    int i;
    for (i=0; i<3000000; i++)
        {
            val->a[i]=n;
            n+=0.0001;
        }
}

int main()
{
    Value *val1=new Value, *val2=new Value;
   
    clock_t start,stop;
   
    start=clock();
    for (int i=0; i<1000; i++)
    {
        thread first (cycle,val1);
        thread second (cycle,val2);
        first.join();
        second.join();
    }
   
    stop=clock();
    float tdiff=(((float)stop - (float)start) / 1000000.0F);
    std::cout<<endl<<"This took "<<tdiff<<" seconds...";
    return 0;
}
'''

3 个答案:

答案 0 :(得分:5)

有一个笑话是这样的:

<块引用>

一个程序员需要1天才能完成一个程序,10个程序员需要多少天? - 10 天。

代码中的工作在此循环中完成:

<块引用>
for (int i=0; i<1000; i++)
{
    thread first (cycle,val1);
    thread second (cycle,val2);
    first.join();
    second.join();
}

现在考虑生成和加入线程是开销。总的来说,您的并行代码所做的不仅仅是顺序代码,在一般情况下没有办法解决这个问题。而且您不是创建和加入线程一次,而是 1000 次,即您添加了 1000 次开销。

不要指望通过简单地向代码添加更多线程来运行得更快。我建议您参考 Amdahl's lawGustavson's Law(基本上相同,只是更积极一点)。

我建议您尝试使用顺序与线程,但只使用一个线程来感受开销。你可以比较一下:

for (int i=0; i<1000; i++)
{
    thread first (cycle,val1);
    first.join();
}

使用不使用任何线程的顺序版本。你会惊讶于这种差异。

当线程执行大量工作(参见 Amdahl/Gustavson)并且不同线程之间没有同步时,您可以充分利用多线程。您加入线程的 1000 次基本上是一个障碍,其中 second 必须等待,直到 first 完成。最好避免此类障碍。

最后但并非最不重要的一点是,如评论中所述,您的基准测试相当有问题,因为您没有使用计算结果。也就是说,要么你没有打开优化,这使得结果变得毫无意义,要么你打开了优化,编译器可能会在你没有注意到的情况下优化掉它。实际上,我不确定您是否正在比较执行相同工作的两个版本,或者您的并行版本是否正在执行两倍的工作。此外,在测量时间时,您需要注意测量挂钟时间而不是 cpu 时间,因为 cpu 时间增加了在多核上花费的时间,而您要比较挂钟时间。

TL;DR:更多线程!= 自动减少运行时间。

答案 1 :(得分:1)

如果您阅读 clock 的文档,您可能会注意到它说如果进程在多个内核上执行,时间似乎会过得更快; clock 是 CPU 使用总量的近似值,而不是“挂钟时间”,并且两个内核并行的一个“CPU 滴答”与一个内核上的两个连续“滴答”的“时间”相同。< br/> (顺便说一句:为了获得以秒为单位的时间,您应该除以 CLOCKS_PER_SEC。)

使用更合适的计时器,例如 std::chrono::steady_clock,将显示顺序变体的时间几乎是多线程版本的两倍。
这种差异完全可以用创建和销毁线程的开销来解释。

答案 2 :(得分:0)

与其他评论所暗示的不同, //Allocating memory for martricesSum variable to add matrices int **martricesSum = ( int** )malloc( sizeof(martricesSum) * rows); //Allocating memory for martricesSum rows for ( int x = 0; x < matrices; x++ ) { martricesSum[x] = (int*)malloc(sizeof(martricesSum[x]) * columns); } //Addition of matrices for ( int u = 0; u < matrices; u++ ) { for ( int v = 0; v < rows; v++ ) { for ( int w = 0; w < columns ; w++ ) { martricesSum[v][w] += arrayMatrices[u][v][w]; } } } //Printing added matrices printf ("\n Addition of above matrices !\n"); for ( int q = 0; q < rows; q++ ) { for ( int r = 0; r < columns; r++ ) { printf ("%3d", martricesSum[q][r]); /*Here something is going wrong Its printing only addresses instead of original values I tried to place a * dereferencing operator (*) before martricesSum[q][r]) but its not working */ } putchar ('\n'); } 不是罪魁祸首,顺序连接也不是。 每个线程都执行相同的操作n,那么怎么会有改进呢? 您必须手动在两个线程之间分配工作负载,以便每个线程处理一半的数据。