自学OpenMP指南【多层for循环】

很多场景下,为了实现某一目标我们会使用多层for循环来解决问题,针对多层for循环如何使用openmp来进行加速,是本篇博客所关注的问题。本篇博客将就着以下3点进行讨论

从一个多层循环的例子说起

先看这么一段代码:

for(int i = 0; i < 2; i++) {
	cout << "first loop"<< endl;
	for (int j = 0; j < 2; j++) {
		cout << "second loop" << endl;
		for (int k = 0; k < 2; k++) {
			printf("third loop i = %d j = %d k = %d \n");
		}
	}
}

以上为0-test.cc,后面会结合这个代码进行改动得到1-test.cc,2-test.cc.3-test.cc

这个案例中一共有3层for循环,每一层都进行了打印操作,我们的目标是对这三层循环进行加速。

首先我们应该清楚openmp能提升运行速度的原因主要时因为并行。不使用openmp,程序是串行的,一个操作接着一个操作进行。但实际上许多操作本身是不互相影响的,因此给提升性能带来了可能,我们可以让程序同一时刻进行多个互相不干扰的程序,进而提升效率。

如果某个程序不同操作之间有影响,难道就不能并行了么?也不全是,并行的程序不能相互影响,因此想要提升相互影响的程序,首先可以先改代码使得不同操作之间没有影响,然后再并行。这个会在后期的其他博客中写,这里按住不提。

就着上一个例子说明,单看最内层的打印操作,可以发现事实上对于最内层的打印来说,这个程序仅仅是重复打印了8次,这8次是互相不干扰的,因此是可以通过并行提升性能的。

重点是我们如何用openmp进行并行。

一些并行尝试

为了更好的解释OpenMP在这里的作用我会用4个例子来具体介绍

1-test.cc
opm_set_num_threads(4)
#pragma omp parallel
for(int i = 0; i < 2; i++) {
 cout << "first loop"<< endl;
 for (int j = 0; j < 2; j++) {
  cout << "second loop" << endl;
  for (int k = 0; k < 2; k++) {
   printf("third loop i = %d j = %d k = %d \n");
  }
 }
}

很遗憾,这个代码并不会提升性能,在#pragma omp parallel的确会生成指定数目的线程个数,但是在1-test.cc的多个线程每个线程都完成了一遍整个程序,因此时间没有减少。

2-test.cc
opm_set_num_threads(4)
#pragma omp parallel
#pragma parallel for
for(int i = 0; i < 2; i++) {
 cout << "first loop"<< endl;
 for (int j = 0; j < 2; j++) {
  cout << "second loop" << endl;
  for (int k = 0; k < 2; k++) {
   printf("third loop i = %d j = %d k = %d \n");
  }
 }
}

这个代码才真正做到了提升效率,并且时间可以减少为原来的一半。

这究竟是什么原因呢?通过查询IBM官方
给出的解释可以知道#pragma omp parallel会进行以下操作:

  • 生成指定数目的线程组
  • 每个线程完成语句生效范围内的所有操作
  • Working-sharing construct区域内的操作将由不同线程分别完成
    IBM官方给出的解释
    #pragam parallel for则完成了working-sharing construct区域建立的功能,因此必须在for循环前面加一个#pragma parallel for才能真正实现并行
3-test.cc

#pragma omp parallel for可以实现2-test.cc中的2行代码的功能

opm_set_num_threads(4)
#pragma omp parallel for
for(int i = 0; i < 2; i++) {
 cout << "first loop"<< endl;
 for (int j = 0; j < 2; j++) {
  cout << "second loop" << endl;
  for (int k = 0; k < 2; k++) {
   printf("third loop i = %d j = %d k = %d \n");
  }
 }
}

结论

对于多层for循环这种代码结构而言,如果最内层for循环各个分支之间互相不影响,则可以通过最外层for循环添加#pragma omp parallel for的方式实现并发。

不过这个方法要特别注意是,多层for循环最内层分支不能互相有影响,而对于有影响的for循环,应该在并发之前改动代码结构,使得内层结构不互相影响,之后才可以进行代码并发化。

并且,不是所有的多层for循环都是可以简单通过一行指令进行并行的,对于更复杂的代码结构,应该先理清代码逻辑,然后改写原代码成可以并行的代码结构,之后进行并行。

猜你喜欢

转载自blog.csdn.net/kullollo/article/details/105732923
今日推荐