OpeMP並行程序設計時需要注意的事項

OpeMP並行程序設計時需要注意的事項

OpeMP程序設計時需考慮一下兩點:
1)當循環次數較少時,如果分成過多的線程來執行的話,可能會使得總的運行時間高於較少線程或一個線程的執行情況,並且會增加能耗;

2)如果設置的線程數量遠大於CPU的核數的話,那麼存在着大量的任務切換和調度的開銷,也會降低整體的效率。

OpenMP只能並行化for循環,它不會並行while和do-while循環,而且只能並行循環次數在for循環外面就確定了的for循環。

    (2)、循環變量只能是整型和指針類型(不能是浮點型)

(3)、循環語句只能是單入口單出口的。循環內部不能改變index,而且裏面不能有goto、break、return。但是可以使用continue,因爲它並不會減少循環次數。另外exit語句也是可以用的,因爲它的能力太大,他一來,程序就結束了。

3)single命令

Single用來指定某塊程序由一個線程執行,除非使用了nowait子句,否則在此線程執行期間其他線程都處於等待狀態,直到遇到single構造快處隱含的barrier。



在並行區域內使用共享變量時,如果存在寫操作,必須對共享變量加以保護;否則,不要輕易使用共享變量,儘量將共享變量的訪問轉化爲私有變量的訪問或者對變量進行加鎖操作。

循環迭代變量在循環構造區域裏是私有的。聲明在循環構造區域內的自動變量是私有。

注意,如果在並行區域內不加鎖保護就直接對共享變量就進行寫操作,存在數據競爭問題,會導致不可預測的異常結果。共享數據作爲private,firstprivate ,lastprivate,threadprivate和reduction子句的參數進入並行區域後,就變成線程私有,不需要加鎖保護。

任務調度

OpenMP中,任務調度主要使用在並行的for循環中。當循環由每次迭代的計算量不等時,如果簡單的將各個線程分配相同的次數的迭代,則會造成各個線程的計算負載不均衡,使得有些線程先執行完,有些後執行完,造成某些CPU核空閒,影響程序性能。

線程同步

1)barrier 是線程同步命令,但是開銷非常大,如果大量使用會引起程序的性能急速下降,因此在程序中應儘量減少barrier命令的使用。

2)critical命令,用在一段代碼臨界區之前,臨界區在同一時間內只能有一個線程執行它,其他線程要執行臨界區的線程則需要排隊來執行它。


需要注意的是,critical命令後的結構快不能從塊中跳出來,也不能從外面跳進去。

3)atomic命令

atomic命令也是對臨界區的一種操作,與critical命令不同的是它對應於操作系統中的原子操作。

 



atomic功能最強大的在於能夠實現對數組進行更新,看如下代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <omp.h> 
void main() 
{
	float *x, *y, *work1, *work2;
	int *index;
	int n, i;
	n = 10;
	x = (float*)malloc(n*sizeof(float));
	y = (float*)malloc(n*sizeof(float));
	work1 = (float*)malloc(n*sizeof(float));
	work2 = (float*)malloc(n*sizeof(float));
	index = (int*)malloc(10 * sizeof(float));
	for (i = 0; i < n; i++) {
		index[i] = (n - i) - 1;
		x[i] = 0.0;
		y[i] = 0.0;
		work1[i] = i;
		work2[i] = i*i;
	}
#pragma omp parallel for  shared(x,y,index,n) 
	for (i = 0; i < n; i++) {
#pragma omp atomic 
		x[index[i]] += work1[i];
		y[i] += work2[i];
	}
	for (i = 0; i < n; i++)
		printf("%d %g %g\n", i, x[i], y[i]);
}


 

發佈了48 篇原創文章 · 獲贊 146 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章