簡體   English   中英

開放MP。 N個線程中的循環並行化

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM