OpenMP 入門( 二 )

openmp 的執行流圖的話就很清晰易懂了 。
積分例子現在我們使用一個簡單的函數積分的例子去具體了解 openmp 在具體的使用場景下的并行 。比如我們求函數\(x^2\) 的積分 。

OpenMP 入門

文章插圖
\[\int_0^{x} x^2 = \frac{1}{3}x^3dx + C\]比如我們現在需要 x = 10 時 , \(x^2\) 的積分結果 。我們在程序里面使用微元法去計算函數的微分結果,而不是直接使用公式進行計算,微元法對應的計算方式如下所示:
\[\int_0^{10} x^2\mathrmdikr8e4r4x =\sum_{ i= 0}^{1000000}(i * 0.00001) ^2 * 0.00001\]微元法的本質就是將曲線下方的面積分割成一個一個的非常小的長方形,然后將所有的長方形的面積累加起來 , 這樣得到最終的結果 。
OpenMP 入門

文章插圖
如果你不懂上面所談到的求解方法也沒關系,只需要知道我們需要使用 openmp 去計算一個計算量比較大的任務即可 。根據上面微元法的公式我們有一個非常大的求和公式,如果是在單線程的情況下我們使用一個循環就可以了,但是現在我們有多個線程 , 那么我們可以讓每個線程求某一個區間的和,最后將各個區間的和加起來得到最終的結果,這就是在并發場景下的實現思路 。
openmp 具體的實現代碼如下所示:
#include <stdio.h>#include <omp.h>#include <math.h>/// @brief 計算 x^2 一部分的面積/// @param start 線程開始計算的位置/// @param end線程結束計算的位置/// @param delta 長方形的邊長/// @return 計算出來的面積double x_square_partial_integral(double start, double end, double delta) {double s = 0;for(double i = start; i < end; i += delta) {s += pow(i, 2) * delta;}return s;}int main() {int s = 0;int e = 10;double sum = 0;#pragma omp parallel num_threads(32) reduction(+:sum){// 根據線程號進行計算區間的分配// omp_get_thread_num() 返回的線程 id 從 0 開始計數 :0, 1, 2, 3, 4, ..., 31double start = (double)(e - s) / 32 * omp_get_thread_num();double end= (double)(e - s) / 32 * (omp_get_thread_num() + 1);sum = x_square_partial_integral(start, end, 0.0000001);}printf("sum = %lf\n", sum);return 0;}在上面的代碼當中 #pragma omp parallel num_threads(4) 表示啟動 4 個線程執行 {} 中的代碼,reduction(+:sum) 表示需要對 sum 這個變量進行一個規約操作,當 openmp 中的線程遇到 reduction 子句的時候首先會拷貝一份 sum 作為本地變量,然后在并行域當中使用的就是每一個線程的本地變量,因為有 reduction 的規約操作,因此在每個線程計算完成之后還需要將每個線程本地計算出來的值對操作符 + 進行規約操作,也就是將每個線程計算得到的結果求和,最終將得到的結果賦值給我們在 main 函數當中定義的變量 sum。最終我們打印的變量 sum 就是各個線程求和之后的結果 。上面的代碼執行過程大致如下圖所示:
OpenMP 入門

文章插圖
注意事項:你在編譯上述程序的時候需要加上編譯選項 -fopenmp 啟動openmp 編譯選項和 -lm 鏈接數學庫 。
上面程序的執行結果如下所示:
OpenMP 入門

文章插圖
總結在本篇文章當中主要給大家介紹了 OpenMP 的基本使用和程序執行的基本原理 , 在后續的文章當中我們將仔細介紹各種 OpenMP 的子句和指令的使用方法,希望大家有所收獲!
更多精彩內容合集可訪問項目:https://github.com/Chang-LeHung/CSCore
關注公眾號:一無是處的研究僧,了解更多計算機(Java、Python、計算機系統基礎、算法與數據結構)知識 。
【OpenMP 入門】

推薦閱讀