[英]OpenMP. Parallelization of the loop in N threads
我正在嘗試使用多個線程並行化 5000 萬次迭代的循環 - 首先是 1,然后是 4、8 和 16。下面是實現此功能的代碼。
#include <iostream>
#include <omp.h>
using namespace std;
void someFoo();
int main() {
someFoo();
}
void someFoo() {
long sum = 0;
int numOfThreads[] = {1, 4, 8, 16};
for(int j = 0; j < sizeof(numOfThreads) / sizeof(int); j++) {
omp_set_num_threads(numOfThreads[j]);
start = omp_get_wtime();
#pragma omp parallel for
for(int i = 0; i<50000000; i++) {
sum += i * 10;
}
#pragma omp end parallel
end = omp_get_wtime();
cout << "Result: " << sum << ". Spent time: " << (end - start) << "\n";
}
}
預計在 4 個線程中程序將比在 1 中運行得快,在 8 個線程中比在 4 個線程中快,在 16 個線程中比在 8 個線程中快,但實際上情況並非如此 - 一切都在混亂中執行速度和幾乎沒有區別。 此外,在任務管理器中看不到程序已並行化。 我有一台具有 8 個邏輯處理器和 4 個內核的計算機。
請告訴我我在哪里犯了錯誤以及如何正確並行化 N 個線程中的循環。
您的代碼中存在競爭條件,因為sum
是同時從多個線程讀取/寫入的。 這應該會導致錯誤的結果。 您可以使用減少指令#pragma omp parallel for reduction(+:sum)
來解決此問題。 請注意,OpenMP 不會檢查您的循環是否可以並行化,這是您的責任。
此外,並行計算可能比順序計算慢,因為聰明的編譯器可以看到sum = 50000000*(50000000-1)/2*10 = 12499999750000000
(AFAIK,Clang 就是這樣做的)。 結果,基准肯定是有缺陷的。 請注意,這肯定大於long
類型可以包含的內容,因此您的代碼中肯定存在溢出。
此外,AFAIK,沒有指令#pragma omp end parallel
之類的東西。
最后,請注意,您可以使用OMP_NUM_THREADS
環境變量控制線程數,這通常比在應用程序中設置它更方便(在應用程序代碼中硬連線給定數量的線程通常不是一個好主意,即使對於基准測試也是如此)。
請告訴我我在哪里犯了錯誤以及如何正確並行化 N 個線程中的循環。
首先,您需要修復代碼示例中的一些編譯器問題。 就像刪除#pragma omp end parallel
之類的編譯指示,正確聲明變量等等。 其次,您需要在更新變量sum
期間修復競爭條件。 該變量在線程之間共享並同時更新。 最簡單的方法是使用 OpenMP 的reduction
子句,您的代碼如下所示:
#include <stdio.h>
#include <omp.h>
int main() {
someFoo();
}
void someFoo() {
int numOfThreads[] = {1, 4, 8, 16};
for(int j = 0; j < sizeof(numOfThreads) / sizeof(int); j++) {
omp_set_num_threads(numOfThreads[j]);
double start = omp_get_wtime();
double sum = 0;
#pragma omp parallel for reduction(+:sum)
for(int i = 0; i<50000000; i++) {
sum += i * 10;
}
double end = omp_get_wtime();
printf("Result: '%d' : '%f'\n", sum, (end - start));
}
}
使用多核運行時,您應該會獲得一些加速。
注意:為了解決@Jérôme Richard 首先提到的溢出問題,我將 'sum' 變量從long更改為double 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.