繁体   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