我试图计算用于矩阵加法的加速和最佳线程数,但是并行执行总是比顺序执行花费更多时间,并且增加持续增加直到大约8个线程,然后变成某种常数。谁能帮我找出原因?
顺序代码:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main (int argc, char *argv[])
{
int ARRAY_SIZE;
int n = 10000;
int n_per_thread;
int i,j;
int *a[n];
int *b[n];
int *c[n];
for (i=0; i<n; i++){
a[i] = (int *)malloc(n * sizeof(int));
b[i] = (int *)malloc(n * sizeof(int));
c[i] = (int *)malloc(n * sizeof(int));
}
for(i=0; i<n; i++) {
for(j=0;j<n;j++){
a[i][j] = 1;
}
}
for(i=0; i<n; i++) {
for(j=0;j<n;j++){
b[i][j] = 1;
}
}
clock_t t;
t = clock();
for(i=0; i<n; i++) {
for(j=0;j<n;j++){
c[i][j] = a[i][j]+b[i][j];
}
}
t = clock() - t;
double time_taken = ((double)t)/CLOCKS_PER_SEC;
printf("Time taken by sequential for matrix size %d: ",n);
printf("%f%s\n",time_taken," seconds");
return 0;
}
并行代码:
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
#include <time.h>
#define NUM_THREADS 10
int main (int argc, char *argv[])
{
int ARRAY_SIZE;
int n = 10000;
int n_per_thread;
int total_threads = NUM_THREADS;
int i,j;
int *a[n];
int *b[n];
int *c[n];
for (i=0; i<n; i++){
a[i] = (int *)malloc(n * sizeof(int));
b[i] = (int *)malloc(n * sizeof(int));
c[i] = (int *)malloc(n * sizeof(int));
}
for(i=0; i<n; i++) {
for(j=0;j<n;j++){
a[i][j] = 1;
}
}
for(i=0; i<n; i++) {
for(j=0;j<n;j++){
b[i][j] = 1;
}
}
omp_set_num_threads(total_threads);
n_per_thread = n/total_threads;
clock_t t;
t = clock();
#pragma omp parallel for shared(a, b, c) private(i) schedule(static, n_per_thread)
for(i=0; i<n; i++) {
for(j=0;j<n;j++){
c[i][j] = a[i][j]+b[i][j];
}
}
t = clock() - t;
double time_taken = ((double)t)/CLOCKS_PER_SEC;
printf("Time taken by parallel for vector size %d: ",n);
printf("%f%s\n",time_taken," seconds");
return 0;
}
答案 0 :(得分:1)
多线程处理无济于事的原因可能是因为bottlenecked是内存带宽而不是CPU速度。
现代台式计算机的内存带宽约为20 GB / s。假设sizeof(int) == 4
,这意味着每秒可以在内存中传输50亿个整数。由于您的每个算术运算均读取2个整数并写入1,因此这意味着现代台式机具有足够的内存带宽,每秒可完成这些算术运算的1.7十亿。因此,现代台式计算机具有足够的内存带宽,可以在一秒钟内用n = 40000
运行程序。
除非您使用的是NUMA架构,否则使用多线程只会增加潜在的计算速度,但不会增加您的内存带宽。
循环代码的单线程版本可能已经由编译器获取了vectorized,这意味着它使用了SIMD指令。至少在激活编译器优化的情况下编译单线程代码时,编译器会这样做。这样,单线程版本的代码已经在很大程度上并行化了。
使用多线程处理当然可以使代码进一步并行化。但是您的计算非常简单,因为您只对每条数据执行一次加法。因此,您的矢量化单线程版本可能不是因为CPU的计算能力而是因为您的内存带宽而成为瓶颈。请参阅以下StackOverflow问题,以获取更多信息,如果循环的矢量化由于内存带宽而受到瓶颈的影响,则有时如何无法为您带来性能上的好处:
Why vectorizing the loop does not have performance improvement
如果您的计算是如此简单,以至于代码的单线程(矢量化)版本都因内存带宽而不是CPU速度而成为瓶颈,那么通过引入多线程来增加更多的计算能力将不会带来太大收益。