日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
OpenMP程序設(shè)計的兩個小技巧

1、動態(tài)設(shè)置并行循環(huán)的線程數(shù)量

永春網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)成立與2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。

在實際情況中,程序可能運行在不同的機器 環(huán)境里,有些機器是雙核,有些機器是4核甚至更多核。并且未來硬件存在升級的可能,CPU核數(shù)會變得越來越多。如何根據(jù)機器硬件的不同來自動設(shè)置合適的線 程數(shù)量就顯得很重要了,否則硬件升級后程序就得進行修改,那將是一件很麻煩的事情。

比如剛開始在雙核系統(tǒng)中開發(fā)的軟件,線程數(shù)量缺省都設(shè)成2,那么當機器升級到4核或8核以后,線程數(shù)量就不能滿足要求了,除非修改程序。

線程數(shù)量的設(shè)置除了要滿足機器硬件升級的可擴展性外,還需要考慮程序的可擴展性,當程序運算量增加或減少后,設(shè)置的線程數(shù)量仍然能夠滿足要求。顯然這也不能通過設(shè)置靜態(tài)的線程數(shù)量來解決。

在具體計算需要使用多少線程時,主要需要考慮以下兩點:

1)當循環(huán)次數(shù)比較少時,如果分成過多數(shù)量的線程來執(zhí)行,可能會使得總運行時間高于較少線程或一個線程執(zhí)行的情況。并且會增加能耗。

2)如果設(shè)置的線程數(shù)量遠大于CPU核數(shù)的話,那么存在著大量的任務切換和調(diào)度等開銷,也會降低整體效率。

那么如何根據(jù)循環(huán)的次數(shù)和CPU核數(shù)來動態(tài)地設(shè)置線程的數(shù)量呢?下面以一個例子來說明動態(tài)設(shè)置線程數(shù)量的算法,假設(shè)一個需要動態(tài)設(shè)置線程數(shù)的需求為:

1、 以多個線程運行時的每個線程運行的循環(huán)次數(shù)不低于4次

2、 總的運行線程數(shù)最大不超過2倍CPU核數(shù)

下面代碼便是一個實現(xiàn)上述需求的動態(tài)設(shè)置線程數(shù)量的例子

 
 
 
  1. const int MIN_ITERATOR_NUM = 4; 
  2.    int ncore = omp_get_num_procs(); //獲取執(zhí)行核的數(shù)量 
  3.    int max_tn = n / MIN_ITERATOR_NUM; 
  4.    int tn = max_tn > 2*ncore ? 2*ncore : max_tn; //tn表示要設(shè)置的線程數(shù)量 
  5. #pragma omp parallel for if( tn > 1) num_threads(tn) 
  6.      for ( i = 0; i < n; i++ ) 
  7.      { 
  8.          printf("Thread Id = %ld/n", omp_get_thread_num()); 
  9.          //Do some work here 
  10.      } 

在上面代碼中,根據(jù)每個線程運行的循環(huán)次數(shù)不低于4次,先計算出最大可能的線程數(shù)max_tn,然后計算需要的線程數(shù)量tn,tn的值等于max_tn和2倍CPU核數(shù)中的較小值。

然后在parallel for構(gòu)造中使用if子句來判斷tn是否大于1,大于1時使用單個線程,否則使用tn個線程,,這樣就使得設(shè)置的線程數(shù)量滿足了需求中的條件。

比如在一個雙核CPU上,n=64,最終會以2倍CPU核數(shù)(4個)線程運行,而不會以max_tn = 64/4=16個線程運行。

在實際情況中,當然不能每個循環(huán)都象上面一樣寫幾行代碼來計算一遍,可以將其寫成一個獨立的功能函數(shù)如下:

 
 
 
  1. const int g_ncore = omp_get_num_procs(); //獲取執(zhí)行核的數(shù)量 
  2.   
  3. /** 計算循環(huán)迭代需要的線程數(shù)量 
  4.      根據(jù)循環(huán)迭代次數(shù)和CPU核數(shù)及一個線程最少需要的循環(huán)迭代次數(shù) 
  5.      來計算出需要的線程數(shù)量,計算出的最大線程數(shù)量不超過CPU核數(shù) 
  6.   
  7.      @param   int n - 循環(huán)迭代次數(shù)   
  8.      @param   int min_n - 單個線程需要的最少迭代次數(shù)    
  9.      @return int - 線程數(shù)量     
  10. */ 
  11. int dtn(int n, int min_n) 
  12.    int max_tn = n / min_n; 
  13.    int tn = max_tn > g_ncore ? g_ncore : max_tn; //tn表示要設(shè)置的線程數(shù)量 
  14.    if ( tn < 1 ) 
  15.    { 
  16.         tn = 1; 
  17.    } 
  18.    return tn; 
  19. 這樣每次并行化循環(huán)時就可以直接使用函數(shù)dtn()來獲取合適的線程數(shù)量,前面的代碼可以簡寫成如下形式: 
  20. #pragma omp parallel for num_threads(dtn(n, MIN_ITERATOR_NUM)) 
  21.      for ( i = 0; i < n; i++ ) 
  22.      { 
  23.          printf("Thread Id = %ld/n", omp_get_thread_num()); 
  24.          //Do some work here 
  25.      } 

當然具體設(shè)置多少線程要視情況而定的,一般情況下線程數(shù)量剛好等于CPU核數(shù)可以取得比較好的性能,因為線程數(shù)等于CPU核數(shù)時,每個核執(zhí)行一個任務,沒有任務切換開銷。

2、嵌套循環(huán)的并行化

在嵌套循環(huán)中,如果外層循環(huán)迭代次數(shù)較少時,如果將來CPU核數(shù)增加到一定程度時,創(chuàng)建的線程數(shù)將可能小于CPU核數(shù)。另外如果內(nèi)層循環(huán)存在負載平衡的情況下,很難調(diào)度外層循環(huán)使之達到負載平衡。

下面以矩陣乘法作為例子來講述如何將嵌套循環(huán)并行化,以滿足上述擴展性和負載平衡需求。

   其實可以采用一個簡單的方法將最外層循環(huán)和第2層循環(huán)合并成一個循環(huán),下面便是采用合并循環(huán)后的并行實現(xiàn)。

 
 
 
  1. void Parallel_Matrix_Multiply(int *a, int row_a, int col_a, 
  2.                      int *b, int row_b,int col_b, 
  3.                      int *c, int c_size ) 
  4.     if ( col_a != row_b ) 
  5.     { 
  6.         return; 
  7.     } 
  8.   
  9.     int i, j, k; 
  10.     int index; 
  11.     int border = row_a * col_b; 
  12.   
  13.     i = 0; 
  14.     j = 0; 
  15. #pragma omp parallel private(i,j,k) num_threads(dtn(border, 1)) 
  16.     for ( index = 0; index < border; index++ ) 
  17.     { 
  18.         i = index / col_b; 
  19.         j = index % col_b; 
  20.   
  21.         int row_i = i * col_a; 
  22.         int row_c = i * col_b; 
  23.   
  24.         c[row_c+j] = 0; 
  25.         for ( k = 0; k < row_b; k++ ) 
  26.         { 
  27.             c[row_c + j] += a[row_i+k] * b[k*col_b+j]; 
  28.         } 
  29.     } 

從上面代碼可以看出,合并后的循環(huán)邊界border = row_a * col_b;即等于原來兩個循環(huán)邊界之積,然后在循環(huán)中計算出原來的外層循環(huán)和第2層循環(huán)的迭代變量i和j,采用除法和取余來求出i和j的值。

需要注意的是,上面求i和j的值必須要保證循環(huán)迭代的獨立性,即不能有循環(huán)迭代間的依賴關(guān)系。不能將求i和j值的過程優(yōu)化成如下的形式:

 
 
 
  1. if ( j == col_b ) 
  2.      j = 0; 
  3.      i++; 
  4. // …… 此處代表實際的矩陣乘法代碼 
  5. j++; 

上面這種優(yōu)化,省去了除法,效率高,但是只能在串行代碼中使用,因為它存在循環(huán)迭代間的依賴關(guān)系,無法將其正確地并行化。

原文鏈接:http://blog.csdn.net/drzhouweiming/article/details/2472454


當前標題:OpenMP程序設(shè)計的兩個小技巧
分享網(wǎng)址:http://www.dlmjj.cn/article/djegsps.html