OpenMP学习笔记
标签(空格分隔): 学习笔记
文章目录
Hello World程序
#include <iostream>
int main()
{
#pragma omp parallel
{
std::cout << "Hello World!\n";
}
}
保存之后用-fopenmp
参数编译
tintin$ g++ test1.cpp -fopenmp
tintin$ ./a.out
Hello World!
咦?说好的多线程并行呢?怎么还是只有一句?
别急这是因为你并没有设置并行参数,所以它默认就使用cpu的核心线程数作为参数
而你的虚拟机在设置的时候只吝啬地给了它单核单线程,所以结果和没有并行的正常代码是一样的
你可以给你的虚拟机重新设置过cpu的配置,也可以手动设置参数
调控Openmp的行为
num_threads(编译指示)
#include <iostream>
int main()
{
/*表示使用5个线程*/
#pragma omp parallel num_threads(5)
{
std::cout << "Hello World!\n";
}
}
此时你运行之后的结果当然是5句熟悉的Hello World了
omp_set_num_threads(运行API)
然而如果一个程序中有很多地方需要用到该设置的话,一个一个地去设置效率不高,而且如果要改动也很麻烦,所以我们可以通过另一个函数来着设置全局的线程参数
#include <omp.h> //需要引入头文件omp.h
#include <iostream>
int main()
{
omp_set_num_threads(5);
#pragma omp parallel
{
std::cout << "Hello World!\n";
}
}
环境变量来调整(环境变量)
tintin$ export OMP_NUM_THREADS=6
tintin$ ./a.out
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
这个时候问题来了,同时使用环境变量和运行时API会出现啥情况呢?
答案是:同时使用环境变量和运行时 API 会出现什么情况?运行时 API 将获得更高的优先权。
一个实例
int main( )
{
int a[1000000], b[1000000];
// ... some initialization code for populating arrays a and b;
int c[1000000];
for (int i = 0; i < 1000000; ++i)
c[i] = a[i] * b[i] + a[i-1] * b[i+1];
// ... now do some processing with array c
}
显然,我们可以将 for 循环分为几个部分,在不同的核心中运行它们,任何 c[k] 与 c 数组中的其他元素都是独立的。
int main( )
{
int a[1000000], b[1000000];
// ... some initialization code for populating arrays a and b;
int c[1000000];
#pragma omp parallel for /*重点在这里*/
for (int i = 0; i < 1000000; ++i)
c[i] = a[i] * b[i] + a[i-1] * b[i+1];
// ... now do some processing with array c
}
parallel for 编译指示可以帮助我们将 for 循环工作负载划分到多个线程中,每个线程都可以在不同的核心上运行,这显著减少了总的计算时间
#include <omp.h>
#include <math.h>
#include <time.h>
#include <iostream>
int main(int argc, char *argv[]) {
int i, nthreads;
clock_t clock_timer;
double wall_timer;
double c[1000000];
for (nthreads = 1; nthreads <=8; ++nthreads) {
clock_timer = clock();
wall_timer = omp_get_wtime();
#pragma omp parallel for private(i) num_threads(nthreads)
for (i = 0; i < 1000000; i++)
c[i] = sqrt(i * 4 + i * 2 + i);
std::cout << "threads: " << nthreads << " time on clock(): " <<
(double) (clock() - clock_timer) / CLOCKS_PER_SEC
<< " time on wall: " << omp_get_wtime() - wall_timer << "\n";
}
}
上面程序可以通过不断增加线程的数量来计算运行内部 for 循环的时间。omp_get_wtime API 从一些任意的但是一致的点返回已用去的时间,以秒为单位。因此,omp_get_wtime() - wall_timer 将返回观察到的所用时间并运行 for 循环。clock() 系统调用用于预估整个程序的处理器使用时间,也就是说,将各个特定于线程的处理器使用时间相加,然后报告最终的结果。