OMP parallel for 不划分迭代
OMP parallel for is not dividing iterations
我正在尝试使用 omp.h 进行分布式搜索。我正在创建 4 个线程。 id 为 0 的线程不执行搜索,而是在海外哪个线程找到了数组中的数字。下面是我的代码:
int arr[15]; //This array is randomly populated
int process=0,i=0,size=15; bool found=false;
#pragma omp parallel num_threads(4)
{
int thread_id = omp_get_thread_num();
#pragma omp cancellation point parallel
if(thread_id==0){
while(found==false){ continue; }
if(found==true){
cout<<"Number found by thread: "<<process<<endl;
#pragma omp cancel parallel
}
}
else{
#pragma omp parallel for schedule(static,5)
for(i=0;i<size;i++){
if(arr[i]==number){ //number is a int variable and its value is taken from user
found = true;
process = thread_id;
}
cout<<i<<endl;
}
}
}
我遇到的问题是每个线程都在执行从 i=0 到 i=14 的循环。根据我的理解,omp 划分了循环的迭代,但这并没有发生在这里。谁能告诉我原因和可能的解决方案?
你的问题是 parallel
里面有一个 parallel
。这意味着来自第一个并行区域的每个线程都会组成一个新团队。这称为嵌套并行性,它是允许的,但默认情况下它是关闭的。所以每个线程创建一个线程组,然后执行它的for循环部分,也就是整个循环。
所以你的 omp parallel for
应该是 omp for
。
但现在还有另一个问题:您的循环将分布在所有线程上,除了线程 0 永远不会进入循环。所以你陷入僵局。
...而您的问题的实际解决方案要复杂得多。它涉及创建两项任务,一项在共享变量上旋转,一项执行并行搜索。
#pragma omp parallel
{
# pragma omp single
{
int p = omp_get_num_threads();
int found = 0;
# pragma omp taskgroup
{
/*
* Task 1 listens to the shared variable
*/
# pragma omp task shared(found)
{
while (!found) {
if (omp_get_thread_num()<0) printf("spin\n");
continue; }
printf("found!\n");
# pragma omp cancel taskgroup
} // end 1st task
/*
* Task 2 does something in parallel,
* sets `found' to true if found
*/
# pragma omp task shared(found)
{
# pragma omp parallel num_threads(p-1)
# pragma omp for
for (int i=0; i<p; i++)
// silly test
if (omp_get_thread_num()==2) {
printf("two!\n");
found = 1;
}
} // end 2nd task
} // end taskgroup
}
}
(您注意到从未执行过的 printf 了吗?我需要它来防止编译器“优化掉”空的 while 循环。)
奖金解决方案:
#pragma omp parallel num_threads(4)
{
if(omp_get_thread_num()==0){ spin_on_found; }
if(omp_get_thread_num()!=0){
#pragma omp for nowait schedule(dynamic)
for ( loop ) stuff
dynamic
和 nowait
的组合可以以某种方式处理丢失的线程。
@Victor Eijkhout 已经解释了这里发生的事情,我只想向您展示一个更简单(并且没有数据竞争)的解决方案。
请注意,OpenMP 的开销很大,在您的情况下,开销大于并行化带来的收益。因此,最好的办法是在这种情况下不要使用并行化。
如果你在循环内做一些昂贵的工作,最简单的解决方案是如果不需要的话跳过这个昂贵的工作。请注意,我在 found = true;
之前使用了 #pragma omp critical
以避免数据竞争。
#pragma omp parallel for
for(int i=0; i<size;i++){
if(found) continue;
// some expensive work here
if(CONDITION){
#pragma omp critical
found = true;
}
}
- 另一种选择是使用
#pragma omp cancel for
#pragma omp parallel
#pragma omp for
for(int i=0; i<size;i++){
#pragma omp cancellation point for
// some expensive work here
if(CONDITION){
//cancelling the for loop
#pragma omp cancel for
}
}
我正在尝试使用 omp.h 进行分布式搜索。我正在创建 4 个线程。 id 为 0 的线程不执行搜索,而是在海外哪个线程找到了数组中的数字。下面是我的代码:
int arr[15]; //This array is randomly populated
int process=0,i=0,size=15; bool found=false;
#pragma omp parallel num_threads(4)
{
int thread_id = omp_get_thread_num();
#pragma omp cancellation point parallel
if(thread_id==0){
while(found==false){ continue; }
if(found==true){
cout<<"Number found by thread: "<<process<<endl;
#pragma omp cancel parallel
}
}
else{
#pragma omp parallel for schedule(static,5)
for(i=0;i<size;i++){
if(arr[i]==number){ //number is a int variable and its value is taken from user
found = true;
process = thread_id;
}
cout<<i<<endl;
}
}
}
我遇到的问题是每个线程都在执行从 i=0 到 i=14 的循环。根据我的理解,omp 划分了循环的迭代,但这并没有发生在这里。谁能告诉我原因和可能的解决方案?
你的问题是 parallel
里面有一个 parallel
。这意味着来自第一个并行区域的每个线程都会组成一个新团队。这称为嵌套并行性,它是允许的,但默认情况下它是关闭的。所以每个线程创建一个线程组,然后执行它的for循环部分,也就是整个循环。
所以你的 omp parallel for
应该是 omp for
。
但现在还有另一个问题:您的循环将分布在所有线程上,除了线程 0 永远不会进入循环。所以你陷入僵局。
...而您的问题的实际解决方案要复杂得多。它涉及创建两项任务,一项在共享变量上旋转,一项执行并行搜索。
#pragma omp parallel
{
# pragma omp single
{
int p = omp_get_num_threads();
int found = 0;
# pragma omp taskgroup
{
/*
* Task 1 listens to the shared variable
*/
# pragma omp task shared(found)
{
while (!found) {
if (omp_get_thread_num()<0) printf("spin\n");
continue; }
printf("found!\n");
# pragma omp cancel taskgroup
} // end 1st task
/*
* Task 2 does something in parallel,
* sets `found' to true if found
*/
# pragma omp task shared(found)
{
# pragma omp parallel num_threads(p-1)
# pragma omp for
for (int i=0; i<p; i++)
// silly test
if (omp_get_thread_num()==2) {
printf("two!\n");
found = 1;
}
} // end 2nd task
} // end taskgroup
}
}
(您注意到从未执行过的 printf 了吗?我需要它来防止编译器“优化掉”空的 while 循环。)
奖金解决方案:
#pragma omp parallel num_threads(4)
{
if(omp_get_thread_num()==0){ spin_on_found; }
if(omp_get_thread_num()!=0){
#pragma omp for nowait schedule(dynamic)
for ( loop ) stuff
dynamic
和 nowait
的组合可以以某种方式处理丢失的线程。
@Victor Eijkhout 已经解释了这里发生的事情,我只想向您展示一个更简单(并且没有数据竞争)的解决方案。
请注意,OpenMP 的开销很大,在您的情况下,开销大于并行化带来的收益。因此,最好的办法是在这种情况下不要使用并行化。
如果你在循环内做一些昂贵的工作,最简单的解决方案是如果不需要的话跳过这个昂贵的工作。请注意,我在
found = true;
之前使用了#pragma omp critical
以避免数据竞争。
#pragma omp parallel for
for(int i=0; i<size;i++){
if(found) continue;
// some expensive work here
if(CONDITION){
#pragma omp critical
found = true;
}
}
- 另一种选择是使用
#pragma omp cancel for
#pragma omp parallel
#pragma omp for
for(int i=0; i<size;i++){
#pragma omp cancellation point for
// some expensive work here
if(CONDITION){
//cancelling the for loop
#pragma omp cancel for
}
}