C++ 并行编程入门:OpenMP 指南

并行编程是将大型任务分解为可以同时执行的较小子任务的过程,从而更有效地利用现有的计算资源。OpenMP 是 C++ 中广泛使用的并行编程 API。它允许开发者通过在现有代码中添加简单的编译器指令,轻松高效地编写并行代码。

OpenMP 的语法

OpenMP 使用编译器指令来指示代码的并行部分。这些指令以 "#pragma" 关键字开头,并采用以下形式:

#pragma omp  [clause[,clause]...]

参数

1. 以下是一些常用的 OpenMP 指令

> – "parallel": 创建一个线程组,并行执行封闭的代码块。

> – "for": 将循环拆分为较小的迭代,这些迭代可以由不同的线程并行执行。

> – "sections": 将封闭的代码块拆分为可以并行执行的不同部分(section)。

> – "single": 指定代码块应仅由一个线程执行。

> – "critical": 指定代码块一次只能由一个线程执行(临界区)。

> – "atomic": 指定对变量的访问应是原子的。

2. clause(子句): 子句为指令提供附加信息。例如,"num_threads" 子句指定用于并行区域的线程数量。

并行编程的步骤

我们需要在编程中实现 (OpenMP) 并行化的步骤如下:

  • 包含 OpenMP 头文件:
#include 
  • 在代码的相关部分添加 OpenMP 指令。
#pragma omp parallel
{
   // Code block to be executed in parallel
   // 将被并行执行的代码块
}

并行编程示例

示例 1: 在这个示例中,我们定义了两个函数 "sumserial" 和 "sumparallel",它们使用 for 循环计算前 n 个自然数的总和。"sumserial" 函数使用串行实现,而 "sumparallel" 函数使用 OpenMP 来并行化 for 循环。然后,我们通过使用 n=100000000 调用这两个函数并使用 chrono 库中的 highresolutionclock 类测量完成任务所花费的时间,来对这两个实现进行基准测试。
以下是上述示例的实现:

C++


CODEBLOCK_5a2f2a43

输出

Serial result: 987459712
Parallel result: 987459712
Serial duration: 0.0942459 seconds
Parallel duration: 0.0658899 seconds
Speedup: 1.43035

示例 2: 在这个示例中,我们将使用以下公式计算圆周率 pi 的近似值:

pi/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...

我们将通过对该公式中的大量项求和来实现这一点,并使用 OpenMP 来并行化执行求和的 for 循环。

computepiserial 函数使用简单的 for 循环以串行方式实现该公式。computepiparallel 函数使用 OpenMP 进行了并行化,带有 #pragma omp parallel for reduction(+:sum) 指令。

main 函数运行代码的串行版本和并行版本,并使用 chrono 库中的 highresolutionclock 类测量每个版本的执行时间。它还计算并行版本实现的加速比。

以下是上述示例的实现:
下面是上述示例的实现:

// C++ Program to implement calculate
// the approximation of pi
// using Parallel Programming
#include 
#include 
#include 

// Serial implementation
// 串行实现
double compute_pi_serial(int n)
{
    double sum = 0.0;
    for (int i = 0; i < n; ++i) {
        int sign = (i % 2 == 0) ? 1 : -1;
        sum += sign / (2.0 * i + 1);
    }
    return 4.0 * sum;
}

// Parallel implementation
// 并行实现
double compute_pi_parallel(int n)
{
    double sum = 0.0;
#pragma omp parallel for reduction(+ : sum)
    for (int i = 0; i < n; ++i) {
        int sign = (i % 2 == 0) ? 1 : -1;
        sum += sign / (2.0 * i + 1);
    }
    return 4.0 * sum;
}

// Driver Function
// 主函数
int main()
{
    const int n = 100000000;

    auto start_time = std::chrono::high_resolution_clock::now();
    double pi_serial = compute_pi_serial(n);
    auto end_time = std::chrono::high_resolution_clock::now();
    std::chrono::duration serial_duration = end_time - start_time;

    start_time = std::chrono::high_resolution_clock::now();
    double pi_parallel = compute_pi_parallel(n);
    end_time = std::chrono::high_resolution_clock::now();
    std::chrono::duration parallel_duration = end_time - start_time;

    std::cout << "Serial Pi: " << pi_serial << std::endl;
    std::cout << "Parallel Pi: " << pi_parallel << std::endl;
    std::cout << "Serial duration: " << serial_duration.count() << " seconds" << std::endl;
    std::cout << "Parallel duration: " << parallel_duration.count() << " seconds" << std::endl;
    std::cout << "Speedup: " << serial_duration.count() / parallel_duration.count() << std::endl;

    return 0;
}

输出

Serial Pi: 3.14159
Parallel Pi: 3.14159
Serial duration: 0.453211 seconds
Parallel duration: 0.123456 seconds
Speedup: 3.67123

(注意:由于并行化的开销和线程调度的随机性,实际运行时间和加速比可能会有所不同。)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/24709.html
点赞
0.00 平均评分 (0% 分数) - 0