为什么没有用于更新阵列的多线程加速

时间:2016-10-14 13:39:25

标签: c++ linux multithreading

在这里,我们编写了一个代码,用于测试多线程的加速更新数组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;
}

2 个答案:

答案 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

我怀疑正在发生的事情是,为这个简单的示例添加线程阻止优化器看到从未使用赋值的结果,因此线程版本实际上填充了向量而单线程版本没有

演示:https://godbolt.org/g/lewly3

答案 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