已解决 - 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;
}
'''
答案 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 law 或 Gustavson'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
,那么怎么会有改进呢?
您必须手动在两个线程之间分配工作负载,以便每个线程处理一半的数据。