Visual C++ 2013 的 STL 平行化函示庫

| | 0 Comments| 11:11
Categories:

之前在《C 14 進行中,來看目前的委員會草案吧~》一文中有提過了,在 C 14 這個尚未定案的 C 新標準裡、又針對了 C 的核心語言、以及標準函示庫(STL)做出了若干的改進。其中,Heresy 覺得相當重要的一部分,就是讓平行化程式開發更簡單的 STL 新函示庫、Parallel STL 了!

而之前在《Modern C : What you need to know》一文也有提過,微軟在 Build 2014 上曾經預告過,將會放出根據《Working Draft, Technical Specification for C Extensions for Parallelism》實作的 Parallel STL 雛型版本;而現在,微軟終於把他放在 CodePlex 上了!

官方的介紹,是《Parallel STL – Democratizing Parallelism in C 》這篇文章,專案的網址則是:

https://parallelstl.codeplex.com/

要下載最新版本的話,基本上就是到「Source Code」裡面、點選右上方的「Download」就可以把整個打包成 ZIP 下載了(連結);而如果有需要的話,也可以用 Git 把整個 clone 下來。


簡介

這套 Parallel STL 基本上算是 STL algorithm(參考)的延伸,所以它的內容基本上都和 STL algorithm 一樣、主要是針對 STL container 做處理;差別只是在於現行的 STL algorithm 提供的含式都是以單一執行序來執行的,而 Parallel STL 所提供的,則都是平行化處理的版本、理論上可以更好地發揮多核心處理器的效能!

而和 OpenMP 相比,Parallel STL 除了也可以透過 for_each() 把迴圈平行化外,主要其實還是他針對一些常見的演算法,提供了平行化的實作;像是 sort()count()reduce()transform()search() 等等,在有需要的時候,都可以直接拿來使用,而不需要自己重新實作,算是相當方便的!

另外,雖然目前他還是只有使用多核心 CPU 來做平行化,但是由於他是定義出一個標準程式介面、然後讓大家自己去實作,所以應該也可以期待、以後可以透過同樣的函式介面,來完成 GPU 的平行化吧~


函式庫準備

由於這個 Parallel STL 基本上還是一個獨立的函式庫,所以如果希望能在自己的專案裡使用的話,需要先把它建置成 lib 和 dll 才行。

在打開 ParallelSTL.sln 這個方案後,裡面可以找到「ParallelSTLDesktop」 這個專案,他基本上就是 Parallel STL 給 native C 用的函式庫了~

在建置好這個專案後,以 x86 的 release 版來說,可以在「release」資料夾下,找到建置出來「ParallelSTL.lib」和「ParallelSTL.dll」檔;至於其他的建置環境(x64、debug 等),所建置出來的檔案則是會在其他對應的目錄下,應該也可以簡單地找到。

再加上「include」目錄下的 header 檔,這樣就可以在其他專案裡面使用 Parallel STL 了。而之後如果所使用的開發環境有直接支援 Parallel STL 的話,就不需要做這些步驟,而可以直接使用了。


程式的撰寫

如果要使用 Parallel STL 的話,程式要做那些修改呢?其實相當簡單!首先,要注意的是:Parallel STL 因為目前還沒定案,還被視為 experimental、實驗性的功能,所以不管是 header 還是 namespace,都還有 experimental 的字樣;這個等正式定案之後,應該是會被拿掉的。

以目前還說,要使用 Parallel STL,基本上就是要 include 「experimental/algorthim」這個檔案;而之後,所有的相關函式,都會在「std::experimental::parallel」這個 namespace 下。

如果以要針對一個 STL 的 container v 做排序來說,使用標準 STL 的寫法,會是類似下面這樣:

using namespace std;
sort(v.begin(), v.end());

而要改用平行化的版本的話,則只需要改成:

using namespace std::experimental::parallel;
sort(par, v.begin(), v.end());

這樣就可以了!

可以看到,除了 namespace 從 std 變成 std::experimental::parallel 外,程式碼的修改,就只有 sort() 這個函式多了一個參數 par,要修改的地方相當地少~

而這邊的 par 是用來告訴 Parallel STL 要怎麼去執行這個函式用的,在現階段的規範裡面,有三種方法:

  • seq:sequential execute、序列化執行、不要平行化
  • par:parallel execute、平行化執行
  • vec:vector execute、向量化執行(維基百科

透過這個參數,就可以在程式裡面簡單地控制是否要平行化、或是要以向量化的方式來執行了。而 Parallel STL 提供的其他函式,也都是類似的狀況,只需要在前面多加這個參數就可以了~

如果是要把迴圈給平行化的化,則是可以使用 for_each() 這個函式,來掃過整個 container;下面就是一個簡單的例子:

using namespace std::experimental::parallel;
for_each(par, vData.begin(), vData.end(), [](int& iVal){
iVal = iVal* iVal;
});

在這個例子裏面,就是透過 for_each() 來對 vData 這個 vector 裡面每一項作平方的計算。這樣的寫法,如果用 OpenMP 的化,則會是:

#pragma omp parallel for
for (int i = 0; i < vData.size(); i)
vData[i] = vData[i] * vData[i];

兩者哪種好用?這就見仁見智了~


簡單的效能測試

以官方提供的「Sort_Sample」這個效能測試用的範例程式來說,在 Heresy 的 Intel Core i7-3612QM 這顆四核心、八執行序的電腦上,其結果摘錄如下:

Testing sort of 100000 ints: 
serial:        0.000 seconds
parallel STL:  0.000 seconds
PPL:           0.000 seconds

Testing sort of 1000000 ints:
serial:        0.031 seconds
parallel STL:  0.000 seconds
PPL:           0.000 seconds

Testing sort of 10000000 ints:
serial:        0.234 seconds
parallel STL:  0.078 seconds
PPL:           0.062 seconds

Testing sort of 50000000 ints:
serial:        1.156 seconds
parallel STL:  0.328 seconds
PPL:           0.328 seconds

Testing sort of 100000000 ints:
serial:        2.437 seconds
parallel STL:  0.671 seconds
PPL:           0.656 seconds

可以看到,如果效能可以量測的話(>=10000000),用 Parallel STL 進行排序所需的時間,大概會是標準、沒有平行化版本的 1/3 – 1/4~這個效能的進步相當多了!


補充:

  • 這個函示庫由於採用新的 C 語法來做開發,所以必須使用 Visual Studio 2013 以後的版本才能使用,如果使用 Visual Studio 2012 則會有編譯錯誤。

  • Parallel STL 在 debug 模式下的效能可能會比沒有平行化更差,如果要做效能測試,請記得使用 release 版。

  • 微軟之前其實也有提供一個平行化的函式庫 Parallel Patterns Library(PPL)可以使用(參考),不過那是 Visual Studio 專用的;而現在的 Parallel STL 則是未來的 C STL 標準函式庫,可以在不同的開發環境使用。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *