在这里,我们编写了一个代码,用于测试多线程的加速更新数组10,000,000次。在一些具有2 * intel E5-2620v2 CPU,centos 6.5,g ++ 4.7.2的机器上,我们发现2-tread比单线程慢得多。 在具有2 * intel E5-2660v2 CPU,centos 6.5,g ++ 4.7.2和windows机器的机器上,我们观察到了加速。如果我们用#34; a [j] = i + j;"替换注释1的代码,我们也获得加速。 两类linux机器的内存带宽相同。
double a[1000];
void test(long long int number){
for(int i =0;i<number;i++){
for(int j = 0;j<1000;j++){
a[j] +=i; //*1*
}
}
}
int main(){
int th = 1;
thread worker[th];
long long int number[th];
for(int i=0; i<th; i++){
number[i] = 10000000/th;
}
struct timeval start, end;
gettimeofday( &start, NULL );
for(int i=0; i<th; i++){
worker[i] = thread(test,number[i]);
}
for(int i=0; i<th; i++){
worker[i].join();
}
gettimeofday( &end, NULL );
double iterate_time =(end.tv_sec-start.tv_sec)+(end.tv_usec-start.tv_usec)/1000000.0;
cout << iterate_time<<endl;
}
答案 0 :(得分:2)
我认为您所看到的是优化器正在消除单线程循环。
long long int number[th];
for(int i=0; i<th; i++){
number[i] = 10000000/th;
}
在此循环之后,永远不会读取分配给number
的结果,因此用数字填充number
的可观察效果与无效的可观察效果相同(参见&#34; as-if rule&#34;)。
你可以通过一个小程序证明这一点:
int main(){
int th = 1;
long long int number[th];
for(int i=0; i<th; i++){
number[i] = 10000000/th;
}
}
与gcc和clang一起进行优化,编译为:
main:
xor eax, eax
ret
我怀疑正在发生的事情是,为这个简单的示例添加线程阻止优化器看到从未使用赋值的结果,因此线程版本实际上填充了向量而单线程版本没有
答案 1 :(得分:2)
给定的示例对于多线程执行是不利的,因为这些任务在线程之间实际上是不可拆分的。
线程争夺单一共享资源:a[1000]
数组。由于cache coherence协议,共享内存上的争用导致高缓存间流量。有关详细信息,请参阅MESI protocol。
争用的实际开销取决于特定的系统,CPU和内存配置。即使在同一台机器上,您也可能会观察到明显不同的结果,具体取决于程序执行的CPU:
// CPUs within the same NUMA node
$ numactl -C 0,1 ./a.out
24.3272
// CPUs from different NUMA nodes
$ numactl -C 0,6 ./a.out
42.1547