【问题标题】:Parallel exection using OpenMP takes longer than serial execution c++, am i calculating execution time in the right way?使用 OpenMP 并行执行比串行执行 c++ 花费更长的时间,我是否以正确的方式计算执行时间?
【发布时间】:2018-04-20 19:49:49
【问题描述】:

Without using Open MP Directives - serial execution - check screenshot here

Using OpenMp Directives - parallel execution - check screenshot here

#include "stdafx.h"
#include <omp.h>
#include <iostream>
#include <time.h>
using namespace std;

static long num_steps = 100000;
double step;
double pi;

int main()
{
clock_t tStart = clock();
int i;
double x, sum = 0.0;
step = 1.0 / (double)num_steps;

#pragma omp parallel for shared(sum)
for (i = 0; i < num_steps; i++)
{
    x = (i + 0.5)*step;
#pragma omp critical
    {
        sum += 4.0 / (1.0 + x * x);
    }
}

pi = step * sum;
cout << pi <<"\n";
printf("Time taken: %.5fs\n", (double)(clock() - tStart) / CLOCKS_PER_SEC);
getchar();
return 0;
}

我试了多次,为什么串行执行总是更快?

串行执行时间:0.0200s 并行执行时间:0.02500s

为什么这里的串行执行速度更快?我是否以正确的方式计算执行时间?

【问题讨论】:

  • 请记住创建线程需要时间,而您的算法不会花费太多时间。
  • 哦,是这样吗,谢谢!
  • 很多事情都会导致并行执行比非并行慢。例如:启动线程的开销超过了每个线程完成的工作。同步的成本超过了并行运行的好处。错误共享(由于错误/无知的实现)会破坏线程版本的性能。还有很多很多。线程是困难不是灵丹妙药。
  • 注意点!感谢您的澄清。
  • 回答您的问题:不,您没有正确计时执行时间。请参阅stackoverflow.com/questions/13351396/… 和其他几个,了解为什么不使用clock 来为并行程序计时。

标签: c++ parallel-processing openmp


【解决方案1】:

OpenMP 在内部实现多线程以进行并行处理,多线程的性能可以通过大量数据来衡量。使用非常少量的数据,您无法衡量多线程应用程序的性能。原因:-

a) 创建线程 O/S 需要为每个线程分配内存,这需要时间(即使它很短。)

b) 当你创建多​​线程时,它需要上下文切换,这也需要时间。

c) 需要释放分配给线程的内存,这也需要时间。

d) 这取决于您机器中的处理器数量和总内存 (RAM)

因此,当您尝试使用多线程进行小型操作时,它的性能将与单线程相同(O/S 默认情况下为每个调用主线程的进程分配一个线程)。所以在这种情况下你的结果是完美的。要衡量多线程架构的性能,使用大量数据和复杂的操作,只有你自己才能看到差异。

【讨论】:

  • 解释清楚!谢谢!
  • 对大多数计算使用关键,您没有利用多个线程。您似乎有一个足够长的循环来有效减少 omp 并行减少。网上一定有这个特定练习的几个例子。
【解决方案2】:

由于您的 critical 块,您不能并行求和 sum。每当一个线程到达critical 部分时,所有其他线程都必须等待。

聪明的方法是为每个线程创建一个 sum 的临时副本,可以在不同步的情况下求和,然后对来自不同线程的结果求和。 Openmp 可以通过 reduction 子句自动执行此操作。所以你的循环将被更改为。

#pragma omp parallel for reduction(+:sum)
for (i = 0; i < num_steps; i++)
{
    x = (i + 0.5)*step;
    sum += 4.0 / (1.0 + x * x);
}

在我的机器上,这比使用 critical 块的版本快 10 倍(我还增加了 num_steps 以减少像线程创建这样的一次性操作的影响)。

PS:我建议你使用&lt;chrono&gt;&lt;boost/timer/timer.hpp&gt;google benchmark 来为你的代码计时。

【讨论】:

  • 添加private(x),因为x 是在共享的并行区域之外定义的,除非您明确将其声明为私有。
  • 对于计时 OpenMP omp_get_wtime() 是一种简单的方法(除了您必须拥有的之外,它不需要任何其他标头或代码)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 2014-05-09
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
相关资源
最近更新 更多