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。可以,採用嵌套並行並不一定能提高效率,只有在合適的地方設置並行才能達到事半功倍的效果。