欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

openMP編程探索2——循環并行化

系統 2223 0

openMP并不是只能對循環來并行的,循環并行化單獨拿出來說是因為它在科學計算中非常有用,比如向量、矩陣的計算。所以我單獨拿出這一部分給大家講講。這里主要講解的是for循環。

編譯指導語句:

一般格式:

#pragma omp parallel for [clause[clause…]]

for(index = first; qualification; index_expr)

{…}

第一句中[]的部分是可選的,由自己的程序并行特點而定。大家先不要把精力放到這里面。后面的文章中會繼續講解的。

并行化for的編寫規則

1、index的值必須是整數,一個簡單的for形式:for(int i = start; i < end; i++){…} 。

2、start和end可以是任意的數值表達式,但是它在并行化的執行過程中值不能改變,也就是說在for并行化執行之前,編譯器必須事先知道你的程序執行多少次,因為編譯器要把這些計算分配到不同的線程中執行。

3、循環語句只能是單入口但出口的。這里只要你避免使用跳轉語句就行了。具體說就是不能使用goto、break、return。但是可以使用continue,因為它并不會減少循環次數。另外exit語句也是可以用的,因為它的能力太大,他一來,程序就結束了。

例子講解

例1、for循環并行

#include
#include "omp.h"
int main(int argc, char* argv[])
{
int i;
#pragma omp parallel for
for (i = 0; i < 12; i++)
{ printf("i = %d %d/n", i, omp_get_thread_num()); }
return 0;
}

例1的執行結果如圖1所示:

image

圖1、例1的執行結果

從結果中可以看出 i 屬于{0,1,2}時由0號線程執行,i 屬于{3,4,5}時由1號線程執行,i 屬于{6,7,8}時由2號線程執行,i 屬于{9,10,11}時由3號線程執行。omp_get_thread_num()這個函數通過執行結果大家也知道了,他返回每個線程的編號。

并行編譯子句

openMP中有多種并行化子句,這些子句都是為控制循環并行化編譯而設定的,這里我們主要關注數據作用域子句,這里的數據作用域是指各個線程是否對某一變量有權訪問。shared子句用來標記變量在各個線程之間是共享的,private子句標記變量在各個線程之間是私有的,實際上它會在在每個線程中保存一個副本。默認情況下,并行執行的變量是共享的。至于其它編譯子句將在后面的文章中介紹。

用實例講解數據作用域子句

實際上我很難想到一個綜合的例子來講解這種子句的限制異同,所以我寫了幾個例子。

例2、private

#include
#include "omp.h"
int main(int argc, char* argv[])
{
float x = 4.3f;
int i;
#pragma omp parallel for private(x)
for (i = 0; i < 12; i++)
{
x = 0;
printf("parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
}
printf("/nserial x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
return 0;
}

image

圖2、例2執行結果

例3 firstprivate(var):指定var在每個線程中都有一個副本,并且var的初始值在并行執行開始之前定義,每個并行線程的var的副本初值就是串行時定義的初始值。程序結束后串行程序中的var值并不會改變。

#include
#include "omp.h"
int main(int argc, char* argv[])
{
float x = 4.3f;
int i;
#pragma omp parallel for firstprivate(x)
for (i = 0; i < 12; i++)
{
x += 1.0f;
printf("parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
}
printf("/nserial x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
return 0;
}

image

圖3、例3的執行結果

例4 lastprivate(var):指定最后多線程執行完后原串行循環最后一次var的值帶到主線程(串行部分)

#include
#include "omp.h"
int main(int argc, char* argv[])
{
float x = 4.3f;
int i;
#pragma omp parallel for lastprivate(x)
for (i = 0; i < 12; i++)
{
x = 0.0f;
printf("parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
}
printf("/nserial x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
return 0;
}

image

圖4、例4的執行結果

例5 firstprivate與lastprivate聯用,很奇怪openMP很多情況下是不允許某個變量被指定兩次規則的,他倆卻可以,呵呵,而且配合效果還不錯。

#include
#include "omp.h"
int main(int argc, char* argv[])
{
float x = 4.3f;
int i;
#pragma omp parallel for firstprivate(x) lastprivate(x)
for (i = 0; i < 12; i++)
{
x += (float)omp_get_thread_num();
printf("parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
}
printf("/nserial x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
return 0;
}

image

圖5、例5的執行結果

從上面的例2、3的程序中可以看出例2中每個線程中x都是私有的,它屬于每個線程,在主線程的定義并不能帶入到各個線程中,使用firstprivate后,x在主線程的初始值可以帶到各個線程中,在圖3可以看出每個線程x的輸出結果實際是相同的,但是在并行執行結束后,主線程中的x值仍然為4.3。從例4的執行結果可以看出最后x的值帶出到了主線程中,這個x值到底是哪個線程中的哪?答案是最后一句x賦值后的值,哪個線程執行完的最晚就是哪個x的值。例5顯示firstprivate與lastprivate聯合使用的執行結果。

例6 reduction規約操作,

執行reduction的變量要特別注意,以reduction(+:sum)為例。

第一種情況:sum為局部變量。這是你必須為sum在串行程序中賦初值,sum 被設置為每個線程私有,先各自執行完算出各自的sum值,最后主線程會將 《線程數+1》個sum變量規約,比如你num_thread(4),在開始并行執行之前你對規約變量賦初值為10,并行時假設每個線程算的的sum值為1,那么最終sum帶到串行程序中的變量值為14(串行的10+四個線程的1)。

第二種情況:sum為全局變量。這是你不必為sum賦初始值,因為此時默認串行的sum值為0,進入每個線程的sum值也是0,規約時仍然是將《線程數+1》個sum值相加,因為你并沒有對全局的sum賦初值,所以最后規約的結果看著像是只有各線程的sum參加了規約操作。其實當你將全局的sum賦初值時,你會發現最后規約的sum值又多加了全局變量sum的串行程序結果。

重要提醒:不管你怎樣設計sum的串行聲明形式,只要他在被定義為規約變量,每次進入并行線程的sum值都是0;

也許你想把每個并行線程的sum值初始化成一個非0的值,然后再各自線程中在使用,那么我可以告訴你,別想了(至少我沒有做到)。因為我規約sum值,如果這個規約有意義你的每個線程應該是各自獨立未回各自的sum的,那么這個初始值使用0就已經非常好了,因為各自的sum計算如果結果一樣,你為何不直接用一句乘法哪(線程數*一個線程計算的sum值)。

#include
#include "omp.h"
int main(int argc, char* argv[])
{
float x = 0.0f;
int i;
float sum = 0.0f;
#pragma omp parallel for private(x) reduction(+:sum)
for (i = 0; i < 12; i++)
{
x = (float)omp_get_thread_num();
sum += x;
printf("parallel sum = %.1f, thread nummber:%d/n", sum, omp_get_thread_num());
}
printf("/nserial sum = %.1f, thread nummber:%d/n", sum, omp_get_thread_num());
return 0;
}

image

圖6、例6執行結果

在例6中我使用了reduction(+:sum),這表示每個線程對sum這個共享變量執行加操作時其它任何線程不能對它進行加操作,實際上我們這樣理解是有偏差的,真正的機理在執行結果中不難看出,實際每個線程都拷貝了一個sum的副本,先在自己執行時加完sum,等所有線程都執行結束后,主線程再將每個線程的sum副本的值加起來返回給主線程中sum。

小結

本節主要講述了for語句的并行化。現在為止大家應該可以熟練使用for并行化了。文章中可能還有些不全面的地方,熱切期望各位讀者能給出批評和指正,期待中……

openMP編程探索2——循環并行化


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 香港三级日本三级人妇网站 | 国产成人免费 | 青娱乐欧美视频 | 欧美激情精品久久久久久久 | 欧日韩在线视频 | 性色成人网 | 欧美一做特黄毛片 | 色秀视频在线观看全部 | 中文字幕在线免费看 | 精品一区二区久久久久久久网站 | 久草在线视频网 | 亚洲精品久久视频 | 不卡久久 | 国产精欧美一区二区三区 | 奇米777四色成人影视 | 潘金莲强完整版 | 国产后式a一视频 | 久久久久久九 | 亚欧视频在线观看 | 国产精品一区久久久 | 火辣福利在线观看 | 五月天婷婷网亚洲综合在线 | 免费成人在线网站 | 欧美一级做 | 日日麻批| 色综合伊人色综合网亚洲欧洲 | 国产在线观 | 亚洲精品手机在线 | 韩国男女无遮挡高清性视频 | 深夜影院破解版免费vip | 9999久久| 二区在线视频 | 日韩不卡一区二区 | 深夜电影网 | 日本永久视频 | 性色av免费在线观看 | 午夜激情视频在线 | 成年视频网站免费观看 | 综合久久久久综合 | 激情91| 91高清视频在线 |