初識openmp 編寫簡單程序並評價其性能

初識OpenMP 編寫簡單程序並評價其性能

摘要

最近導師在給我們講授高性能計算的課程,然後佈置了一個任務是學習OpenMP並會簡單的編程,然後再測量其性能。
之前完全沒有聽過這個詞,從維基百科上查閱了下,然後根據自己理解做了一些總結並進行了簡單的程序測試及性能評估。供大家參考!

一、OpenMP介紹

  • 定義
    OpenMP是Open Multi-Processing的簡稱,維基上給出的定義:OpenMP是一套支持跨平臺共享內存方式的多線程併發的編程API,使用C,C++和Fortran語言,可以在大多數的處理器體系和操作系統中運行。
    它實際上就是一套便於開發的應用程序接口,程序員在編寫代碼時可以直接調用庫函數中定義好的函數而不用自己再去編寫,和其他大部分API是一樣的,用哪個學哪個調用哪個就行,和我們查字典一樣。
    但這套API 的功能是針對共享內存並行系統的多線程程序設計而存在的,顧名思義它對於非共享內存系統(如計算機集羣)無效,這也是OpenMP的一個缺點。
  • 多線程及並行程序
    然後再來說一下多線程,舉一個很簡單的例子,假設正值售票高峯期,只有一個窗口售票,售票員只能一個一個的服務,你去排隊買票,你覺得你什麼時候能買到?所以一般售票處窗口不止一個,多個窗口同時進行售票服務,這就是多線程的基本思想。同樣的,對於計算機來說,單處理器的計算效能肯定不如多處理器,現如今雙核、四核的 CPU 當道,而六核的CPU也已經面世多時,所以在多處理機上編寫、運行並行程序會變得相當普遍。
    我們通常所寫的程序屬於單一執行緒的程式(single thread 單線程),多核心的處理器並沒有辦法提升它的處理效能;不過對於多執行緒的程式(multi thread 多線程),就可以通過不同的內核同時計算,來達到加速的目的。簡單的例子,以單線程來說,計算1+1=2要十秒的話,做十次,如果都丟給同一個內核,就是 10 秒 * 10 次,即 100 秒;而多線程,它可以把計算式分給兩個cpu去做,每個各做 5 次,所以需要的時間就只有 50 秒! 我們可以把這種分配計算理解爲並行處理,所寫的程序即並行程序。
    寫程序的時候該怎麼去寫這樣的程序呢?一般的方法,就是利用線程的控制,去產生多個 thread。由主線程把工作拆開,分給子線程去運算,最後再由主線程回收結果、整合。
  • OpenMP優勢
    但是,實際上要去控制線程是很麻煩的,在程序的編寫上,也會複雜不少。而OpenMP是一個跨平臺的多線程實現,它可以通過高階指令,很簡單地將程式並行化、多線程化;將主線程(順序的執行指令)生成一系列的子線程,並將任務劃分給這些子線程進行執行。這些子線程並行的運行,由運行時環境將線程分配給不同的處理器。假如我們只是想要把一些簡單的循環並行化處理,最簡單的情形,只加一行指令,就可以將循環內的程序並行化處理了!
    瞭解了以上這些概念,不難理解OpenMP是什麼樣的API了,它是爲在多處理機上編寫並行程序而設計的一個應用編程接口。它提供了對並行算法的高層的抽象描述,降低了並行編程的難度和複雜度,這樣程序員可以把更多的精力投入到並行算法本身,而非其具體實現細節。程序員只需通過在源代碼中加入專用的pragma(OpenMP 的語法)來指明自己的意圖,由此編譯器可以自動將程序進行並行化,並在必要之處加入同步互斥以及通信。當選擇忽略這些pragma,或者編譯器不支持OpenMP時,程序又可退化爲通常的程序(一般爲串行),代碼仍然可以正常運作,只是不能利用多線程來加速程序執行。
  • 其它
    OpenMP包括一套編譯指導語句和一個用來支持它的函數庫。
#pragma omp <directive> [clause[[,] clause] ...]

其中,directive共11個;clause13個;
OpenMP還定義了20多個庫函數,具體用法在這裏不一一列舉了,大家可以直接在維基百科或者官網查看。

二、簡單程序編寫

  • OpenMP配置
    我用的是visual studio 2019 ,打開程序——創建新項目在這裏插入圖片描述
    依次選擇後下一步在這裏插入圖片描述
    項目名稱——存儲位置——創建在這裏插入圖片描述
    解決方案資源管理器——源文件右擊——添加——新建項——c++文件——名稱後綴改爲.c——添加在這裏插入圖片描述
    項目——屬性——c/c++——語言——openmp支持打開——應用確定
    在這裏插入圖片描述
  • 代碼測試
    將維基百科中Hello, world的例子稍微做了點改動。
    1.首先測試串行程序,Hello, world打印100000次所花費的時間。
/*串行測試*/
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
int main(int argc, char* argv[])
{
    double t1, t2;
    t1 = clock();
    for (int i = 0; i < 100000; i++)
        printf("Hello, world.\n");
    t2 = clock();
    printf("%fs", (t2 - t1) * 0.001);
    return 0;
}

運行結果:
在這裏插入圖片描述
2.其次測試openmp的並行效果。這裏注意:編寫帶編譯指令的並行程序時,一定要加上<omp.h>頭文件,OpenMP的函數都聲明在頭文件omp.h中。

/*openmp並行測試*/
#include<omp.h>
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
int main(int argc, char* argv[])
{
    double t1, t2;
    int i;
    t1 = clock();
#pragma omp parallel for
    for (i = 0; i < 100000; i++)
        printf("Hello, world.\n");
    t2 = clock();
    printf("%fs", (t2 - t1) * 0.001);
    return 0;
}

運行結果:
在這裏插入圖片描述

三、性能評價

通過以上實驗結果,可以看到,串行和並行相差的時間並不是很多,我運行了至少有五十次,結果甚至是串行所用時間更短,預期的結果應該是多線程速度會有明顯的提升,但在這裏,不知道是循環代碼過於簡單,還是因爲硬件的關係,因爲電腦的是單核的。剛接觸openmp,還是遇到了困難,希望有大神指點,互相學習!

參考

https://baike.tw.wjbk.site/wiki/OpenMP

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章