这两者有什么区别?
[A]
#pragma omp parallel
{
#pragma omp for
for(int i = 1; i < 100; ++i)
{
...
}
}
[B]
#pragma omp parallel for
for(int i = 1; i < 100; ++i)
{
...
}
答案 0 :(得分:59)
我认为没有任何区别,一个是另一个的捷径。虽然您的确切实施可能会以不同方式处理它们
组合的并行工作共享结构是一种快捷方式 指定包含一个工作共享构造的并行构造 而且没有其他声明。允许的条款是条款的结合 允许并行和工作共享结构。
取自http://www.openmp.org/mp-documents/OpenMP3.0-SummarySpec.pdf
OpenMP的规范如下:
答案 1 :(得分:56)
这些是等效的。
#pragma omp parallel
产生一组线程,而#pragma omp for
在产生的线程之间划分循环迭代。您可以使用融合的#pragma omp parallel for
指令同时执行这两项操作。
答案 2 :(得分:24)
以下是使用分隔parallel
和for
here的示例。简而言之,它可以在多个线程中执行for
循环之前用于动态分配OpenMP线程专用数组。
在parallel for
案例中进行相同的初始化是不可能的。
UPD: 在问题示例中,单个pragma和两个pragma之间没有区别。但实际上,您可以使用分离的parallel和for指令来创建更多线程感知行为。 一些代码例如:
#pragma omp parallel
{
double *data = (double*)malloc(...); // this data is thread private
#pragma omp for
for(1...100) // first parallelized cycle
{
}
#pragma omp single
{} // make some single thread processing
#pragma omp for // second parallelized cycle
for(1...100)
{
}
#pragma omp single
{} // make some single thread processing again
free(data); // free thread private data
}
答案 3 :(得分:8)
虽然具体示例的两个版本都是等效的,但正如其他答案中已经提到的那样,它们之间仍然存在一个小的差异。第一个版本包含一个不必要的隐含障碍,在&#34; omp结束时遇到&#34;。可以在并行区域的末尾找到另一个隐式屏障。添加&#34; nowait&#34; &#34; omp for&#34;会使两个代码等效,至少从OpenMP的角度来看。我之所以提到这一点,是因为OpenMP编译器可能会为这两种情况生成略有不同的代码。
答案 4 :(得分:5)
当我在g ++ 4.7.0中进行for循环时,我看到了截然不同的运行时 并使用
std::vector<double> x;
std::vector<double> y;
std::vector<double> prod;
for (int i = 0; i < 5000000; i++)
{
double r1 = ((double)rand() / double(RAND_MAX)) * 5;
double r2 = ((double)rand() / double(RAND_MAX)) * 5;
x.push_back(r1);
y.push_back(r2);
}
int sz = x.size();
#pragma omp parallel for
for (int i = 0; i< sz; i++)
prod[i] = x[i] * y[i];
串行代码(无openmp
)在79毫秒内运行。
“并行”代码在29毫秒内运行。
如果我省略for
并使用#pragma omp parallel
,则运行时最长可达179毫秒,
这比串行代码慢。 (该机器的并发性为8)
代码链接到libgomp
答案 5 :(得分:4)
显然有很多答案,但是这个答案很好(带有源代码)
#pragma omp for
仅将循环的一部分委派给 当前团队中的不同线程。团队是线程组 执行程序。在计划开始时,团队仅包含一个 单个成员:运行程序的主线程。要创建新的线程组,您需要指定并行 关键词。可以在周围的上下文中指定它:
#pragma omp parallel { #pragma omp for for(int n = 0; n < 10; ++n) printf(" %d", n); }
和:
什么是:平行的,为了和一个团队
平行, 和for并行,如下所示:
团队是线程组 当前执行的。在计划开始时,团队包括 一个线程。并行构造将当前线程拆分为一个 在下一个阻止/声明的持续时间内有新的线程组, 之后,团队合并为一体。为划分工作 在当前团队的线程中进行循环。
它不会创建 线程,它仅将工作分配给当前线程 执行团队。 parallel for是一次两个命令的简写: 并行和。 Parallel创建了一个新团队,并进行了分组 团队来处理循环的不同部分。如果您的程序从未 包含一个并行构造,线程永远不止一个; 启动程序并运行它的主线程,如 非线程程序。
答案 6 :(得分:0)
TL;DR:唯一的区别在于第一个代码调用了两个隐式障碍,而第二个代码只调用了一个。
使用官方 OpenMP 5.1 标准作为参考的更详细答案。
#pragma omp parallel
:
将创建一个由 parallel region
组成的团队的 threads
,其中每个线程将执行 parallel region
包含的整个代码块。
从 OpenMP 5.1 可以阅读更正式的描述:
<块引用>当一个线程遇到并行结构时,一组线程 创建以执行并行区域 (..)。这 遇到并行构造的线程成为主线程 新团队的线程,持续时间内线程数为零 新的平行区域。 新团队中的所有线程,包括 主线程,执行区域。 创建团队后, 团队中的线程数在持续时间内保持不变 那个平行区域。
:
#pragma omp parallel for
将创建一个 parallel region
(如前所述),并且将使用 threads
将其包含的循环的迭代分配给该区域的 default chunk size
,并且default schedule
这是通常 static
。但是请记住,default schedule
可能因 OpenMP
标准的不同具体实现而异。
您可以从 OpenMP 5.1 中阅读更正式的描述:
<块引用>worksharing-loop 结构指定一个或 更多关联的循环将由线程并行执行 团队在他们隐性任务的背景下。 迭代是 分布在团队中已经存在的线程中 执行工作共享循环区域所在的并行区域 绑定。
<块引用>并行循环结构是指定并行循环的快捷方式 包含具有一个或多个关联的循环结构的结构 循环,没有其他语句。
或者非正式地说,#pragma omp parallel for
是构造函数 #pragma omp parallel
和 #pragma omp for
的组合。
您拥有的带有 chunk_size=1
和 static schedule
的两个版本都会导致类似:
在代码方面,循环将被转换为逻辑上类似于:
for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{
//...
}
<块引用>
omp_get_thread_num 例程返回线程号,在 调用线程的当前团队。
<块引用>返回当前团队中的线程数。在一个连续的 omp_get_num_threads 程序部分返回 1。
或者换句话说,for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)
。其中 THREAD_ID
的范围从 0
到 TOTAL_THREADS - 1
,TOTAL_THREADS
表示在并行区域上创建的团队线程总数。