我正在尝试使用OpenMP并行化一个简单的循环。下面是我的代码:
#include <iostream>
#include <omp.h>
#include <time.h>
#define SIZE 10000000
float calculate_time(clock_t start, clock_t end) {
return (float) ((end - start) / (double) CLOCKS_PER_SEC) * 1000;
}
void openmp_test(double * x, double * y, double * res, int threads){
clock_t start, end;
std::cout << std::endl << "OpenMP, " << threads << " threads" << std::endl;
start = clock();
#pragma omp parallel for num_threads(threads)
for(int i = 0; i < SIZE; i++){
res[i] = x[i] * y[i];
}
end = clock();
for(int i = 1; i < SIZE; i++){
res[0] += res[i];
}
std::cout << "time: " << calculate_time(start, end) << std::endl;
std::cout << "result: " << res[0] << std::endl;
}
int main() {
double *dbl_x = new double[SIZE];
double *dbl_y = new double[SIZE];
double *res = new double[SIZE];
for(int i = 0; i < SIZE; i++){
dbl_x[i] = i % 1000;
dbl_y[i] = i % 1000;
}
openmp_test(dbl_x, dbl_y, res, 1);
openmp_test(dbl_x, dbl_y, res, 1);
openmp_test(dbl_x, dbl_y, res, 2);
openmp_test(dbl_x, dbl_y, res, 4);
openmp_test(dbl_x, dbl_y, res, 8);
delete [] dbl_x;
delete [] dbl_y;
delete [] res;
return 0;
}
我如下编译
g++ -O3 -fopenmp main.cpp -o ompTest
但是,在Core-i7上运行测试后,我得到以下结果:
OpenMP,1个线程
时间: 31.468
结果:3.32834e + 12
OpenMP,1个线程
时间: 18.663
结果:3.32834e + 12
OpenMP,2个线程
时间: 34.393
结果:3.32834e + 12
OpenMP,4个线程
时间: 56.31
结果:3.32834e + 12
OpenMP,8个线程
时间: 108.54
结果:3.32834e + 12
我不明白我在做什么错?为什么OpenMP会减慢计算速度?
而且,为什么第一个结果比第二个(两个线程都带有1个omp线程)要慢得多?
我的测试环境:Core i7-4702MQ CPU @ 2.20GHz,Ubuntu 18.04.2 LTS,g++ 7.4.0。
最佳答案
至少有两件事正在发生。
clock()
衡量经过的处理器时间,可以将其视为执行的工作量的度量,而您要衡量经过的墙壁时间。参见OpenMP time and clock() calculates two different results。 与您的代码中的这种变化进行比较,该代码实现了一种更合适的方法来测量经过的墙壁时间:
float calculate_time(struct timespec start, struct timespec end) {
long long start_nanos = start.tv_sec * 1000000000LL + start.tv_nsec;
long long end_nanos = end.tv_sec * 1000000000LL + end.tv_nsec;
return (end_nanos - start_nanos) * 1e-6f;
}
void openmp_test(double * x, double * y, double * res, int threads){
struct timespec start, end;
std::cout << std::endl << "OpenMP, " << threads << " threads" << std::endl;
clock_gettime(CLOCK_MONOTONIC, &start);
#pragma omp parallel num_threads(threads)
for(int i = 0; i < SIZE; i++){
res[i] = x[i] * y[i];
}
clock_gettime(CLOCK_MONOTONIC, &end);
for(int i = 1; i < SIZE; i++){
res[0] += res[i];
}
std::cout << "time: " << calculate_time(start, end) << std::endl;
std::cout << "result: " << res[0] << std::endl;
}
对我来说结果是
请注意,两个线程的测量时间如何减少一半,但是增加更多的内核并不能带来多大的改善,最终开始趋向于单线程时间。*这显示出在我的计算机上同时执行更多工作的竞争效果。四核,八超线程计算机,以及与更多线程进行协调相关的开销和资源争用增加。
底线:在任务上抛出更多线程并不一定会更快地获得结果,并且很少会使您获得与线程数成比例的加速比。
*全面披露:我从几次运行的结果中挑选出了这些特别的结果。所有人都显示出相似的趋势,但是这一趋势在这一趋势中特别明显-因此可能过分强调了。