嵌套並行

OpenMP中不建議使用並行嵌套,如果一個並行計算中的某個線程遇到了另外一個並行分支,程序運行將會變得不穩定。將一個完整的工作任務通過一組並行線程分成若干小任務,每個線程只執行指定給它的那段代碼,並沒用多餘的線程去做其他的工作,即使並行計算中正在運行的某個線程遇到了一個新的並行分支,通過分割這個任務形成更多的線程,這並沒有任何實際意義。因此,嵌套並行在OpenMP中將不考慮。OpenMP在處理多級並行嵌套時默認採用串行的執行方式,所以採用多級的並行在程序執行上並不會獲得更高的計算效率。

下面通過一個例子來說明OpenMP中的並行嵌套。代碼如下:

//File :NestingTest.cpp
#include"stdafx.h"
#include<omp.h>
#include<iostream>
using namespace std;
void NestingTest()
{
	int i,j;
	#pragma omp parallel for
	for(i=0;i<4;i++)
	{
		#pragma omp parallel for
		for(j=0;j<4;j++)
		{
			cout<<"j  Threads:"<<omp_get_num_threads()<<"  ThreadID:"<<omp_get_thread_num()<<"\n";
		}
		cout<<"  i="<<i<<"  Threads:"<<omp_get_num_threads()<<"\n";		
	}	
}

這是一個簡單的並行嵌套,運行結果如下:

j  Threads:j Threads:1 

ThreadID:01  ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

 i=2  Threads:8

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

j  Threads:1 ThreadID:0

  i=3  Threads:8

  i=0  Threads:8

j  Threads:1 ThreadID:0

  i=1  Threads:8

從輸出結果可以發現,在i的循環中循環之間處於並行狀態,而在j中循環屬於串行。默認情況下即使將j循環定義成並行,其內部執行時仍然按串行方式運行。

若需要使用嵌套並行,則需要使用omp_set_nested()函數設置在程序中可用並行嵌套。如下例子:

//File :NestedTest.cpp
#include"stdafx.h"
#include<omp.h>
#include<iostream>
using namespace std;
void NestedTest()
{
	int i,j,k;
	k=omp_get_nested();
	cout<<"是否支持並行嵌套:"<<k<<"\n";
	omp_set_nested(1);//設置支持嵌套並行
	k=omp_get_nested();
	cout<<"是否支持並行嵌套:"<<k<<"\n";
	double starttime,endtime;
	starttime=omp_get_wtime();
	#pragma omp parallel for
	for(i=0;i<2;i++)
	{
		#pragma omp parallel for
		for(j=0;j<4;j++)
		{
			cout<<"  i="<<i<<"  j="<<j<<"  Threads:"<<omp_get_num_threads()<<"  ThreadID:"<<omp_get_thread_num()<<"\n";
		}
		cout<<"  I="<<i<<"  Threads:"<<omp_get_num_threads()<<"  ThreadID:"<<omp_get_thread_num()<<"\n";
	}	
	endtime=omp_get_wtime();
	k=omp_get_nested();
	cout<<"是否支持並行嵌套:"<<k<<"\n";
	cout<<"計算耗時:"<<endtime-starttime<<"s\n";
}

運行程序,其結果如下:

是否支持並行嵌套:0

是否支持並行嵌套:1

  i= i=1  j=2  Threads:8 i=0  j=0  Threads:8 ThreadID:0

  ThreadID:2

  i=0 j=3  Threads:8  ThreadID:3

  i=0 j=1  Threads:8  ThreadID:1

  i=1 j=3  Threads:8  ThreadID:3

  i=1 j=1  Threads:8  ThreadID:1

0  j=2 Threads:8  ThreadID:2

  i=1 j=0  Threads:8  ThreadID:0

  I=0  Threads:8 ThreadID:0

  I=1  Threads:8 ThreadID:1

是否支持並行嵌套:1

計算耗時:0.0338853s

從上面結果可見,不僅在i的循環中每個循環處於並行,在j中每個循環也處於並行狀態。默認情況下,程序的並行嵌套是不可用的,即並行中的並行將會當作串行來處理。如果使用omp_set_nested()設置其可用並行嵌套,則當並行中的線程遇到新的並行時,會創建新的線程來並行處理。

下面用一個例子來比較嵌套並行與非嵌套並行的運行效率,代碼如下:

//File :NestingTest02.cpp
#include"stdafx.h"
#include<omp.h>
#include<iostream>
using namespace std;
void test()
{
	int i;
	for(i=0;i<100000000;i++);
}
void NestingTest02()
{
	int i,j;
	double starttime,endtime;
	starttime=omp_get_wtime();
	#pragma omp parallel for
	for(i=0;i<8;i++)
	{
		#pragma omp parallel for
		for(j=0;j<8;j++)
		{
			test();
		}		
	}	
	endtime=omp_get_wtime();
	cout<<"計算耗時:"<<endtime-starttime<<"s\n";		
}

上面代碼是一個嵌套並行,其計算耗時約爲2.63688s。如果將j循環上面的並行指令註釋,只有一個並行結構,其結果爲0.678552s。如果將i循環上面的並行指令註釋,保留j循環前面的並行指令,其結果爲2.67237s。如果都不採用並行,直接用串行運行,其計算耗時爲16.1329s。可以,採用嵌套並行並不一定能提高效率,只有在合適的地方設置並行才能達到事半功倍的效果。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章