我正在阅读有关OpenMP的内容,这听起来很棒。我发现作者声称可以使用#pragma omp parallel
来创建一个新的线程团队。所以我想知道#pragma omp parallel
在这里有什么区别。我读到#pragma omp for
使用当前的线程团队来处理for循环。所以我有两个例子
第一个简单的例子:
#pragma omp for
for(int n=0; n<10; ++n)
{
printf(" %d", n);
}
printf(".\n");
第二个例子
#pragma omp parallel
{
#pragma omp for
for(int n=0; n<10; ++n) printf(" %d", n);
}
printf(".\n");
我的问题是每次运行时创建的线程,还是应用程序启动时创建的线程,或者我为什么要创建更多线程的团队?
答案 0 :(得分:3)
你的第一个例子不会那样编译。 “#pragma omp for”建议编译器在必须首先创建的线程团队中分配以下循环的工作负载。在第二个示例中使用时,使用“#pragma omp parallel”语句创建一组线程。您可以使用“#pragma omp parallel for”组合“omp parallel”和“omp for”指令 线程组是在并行语句之后创建的,并且在此块中有效。
答案 1 :(得分:1)
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
表示在并行区域上创建的团队线程总数。
答案 2 :(得分:0)
- “并行”区域可以包含多个简单的“for”循环。 在你的程序第一次遇到“并行”时,开放的MP线程团队将被创建,之后,每个开放的mp构造将重用那些线程用于循环,部分,任务等......