linux 平行計算之 openmp初探
一:簡介
OpenMP(Open Multi-Processing)是一種共享記憶體程式設計模式,多執行緒並行應用程式介面,使用C,C++和Fortran語言。由兩種形式實現並行功能:編譯指導語句和執行時庫函式。編譯指導語句告訴程式何時開始並行,庫函式用來設定執行緒數及實現其它並行功能。
二:兩個小程式
1. Hello_World.c 的並行
#include <stdio.h> #include <omp.h>//呼叫Openmp庫函式 #define N 6 int main(int argc, char *argv[]) { int i; printf ("*Hello World! Thread: %d\n", omp_get_thread_num()); #pragma omp parallel for for (i = 0; i < N; ++i) printf ("Hello World! Thread: %d, i: %d\n", omp_get_thread_num(), i); return 0; }
其中:#pragma omp parallel for 是編譯指導語句,宣告下面的for語句要並行多執行緒執行。
omp_get_thread_num()是執行時的庫函式,用來獲取當前的執行緒號。
通過命令列
gcc -fopenmp Hello_World_omp.c -o hw_opmp
編譯,生成可執行檔案。執行程式:
./hw_opmp
結果如下:
$ ./hw_opmp *Hello World! Thread: 0 Hello World! Thread: 2, i: 4 Hello World! Thread: 1, i: 2 Hello World! Thread: 1, i: 3 Hello World! Thread: 0, i: 0 Hello World! Thread: 0, i: 1 Hello World! Thread: 3, i: 5
可以看到,沒有並行時,預設只有一個執行緒,ID 為0;當並行時,有4個執行緒,即通過4個CPU 來同時處理,我的電腦只有4個CPU 核心。
2. matrix_multiply_openmp.cpp
#include<iostream> #include<omp.h> #include<time.h>//記錄程式執行時間 using namespace std; int main() { int Matrix1[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int Matrix2[4][2]={2,3,5,4,7,9,8,0}; int Matrix[3][2]; clock_t start, end;//宣告型別為clock_t cout<<"Matrix1:\n"; int i,j,k; for(i=0;i<3;i++){ for(j=0;j<4;j++){ cout<<Matrix1[i][j]<<'\t'; } cout<<endl; } cout<<"Matrix2:\n"; for(i=0;i<4;i++){ for(j=0;j<2;j++){ cout<<Matrix2[i][j]<<'\t'; } cout<<endl; } for(i=0;i<3;i++){ for(j=0;j<2;j++){ Matrix[i][j]=0; } } omp_set_num_threads(3); int pnum=omp_get_num_procs(); cout<<"Thread_pnum ="<<pnum<<endl; start=clock();//開始計時 #pragma omp parallel shared(Matrix1, Matrix2, Matrix) private(j,k) { #pragma omp for schedule(dynamic) for(i=0;i<3;i++){ cout<<"Thread_num:"<<omp_get_thread_num()<<'\n'; for(j=0;j<2;j++){ for(k=0;k<4;k++){ Matrix[i][j]=Matrix[i][j]+Matrix1[i][k]*Matrix2[k][j]; } } } } end=clock(); cout<<"Matrix multiply time:"<<(double (end-start))/CLOCKS_PER_SEC<<endl; //CLOCKS_PER_SEC為每秒敲鐘數,end-start是從開始到程式結束的總敲鐘數 cout<<"The result is:\n"; for(i=0;i<3;i++){ for(j=0;j<2;j++){ cout<<Matrix[i][j]<<'\t'; } cout<<endl; } return 0; }
其中:omp_set_num_threads(3); 設定程序數為3 omp_get_num_procs(); 獲取本機處理器核數,我的是4核。
#pragma omp parallel shared(Matrix1, Matrix2, Matrix) private(j,k) 編譯指導語句,並設定Matrix1,Matrix2, Matrix為共享,j,k為私有。這是為了讓3個程序都能使用Matrix1,Matrix2, Matrix,但每個程序計算自己的向量運算。 #pragma omp for //schedule(dynamic) 編譯指導語句,宣告下面的for迴圈,即第一個for迴圈進入3執行緒的平行計算。由於Matrix1是3行,故每個執行緒處理一行。schedule(dynamic)動態的為空閒程序分配指定大小的迴圈塊。
注意:並行化for的注意事項:
(1)迴圈語句規範,易於判斷迴圈次數;
(2)迴圈中不能包含允許迴圈提前退出的語句(將改變迴圈次數),如:break, return, exit.
命令列編譯:
g++ -fopenmp matrix_multiply_openmp.cpp -o mm_openmp
c++原始檔的編譯使用g++, c原始檔的編譯使用gcc。
執行
./mm_openmp
$ ./mm_openmp
Matrix1:
1 2 3 4
5 6 7 8
9 10 11 12
Matrix2:
2 3
5 4
7 9
8 0
Thread_pnum =4
Thread_num:Thread_num:Thread_num:0
2
3
Matrix multiply time:0.007634
The result is:
65 38
153 102
241 166
可以看到程式使用了ID 為0,2,3的程序來處理第一個for迴圈。