使用 OpenMP 任务的带有 break 的并行 for 循环
Parallel for loop with break using OpenMP tasks
我是 OpenMP 的初学者,正在学习有关任务的知识,并希望将它们应用到以下场景中。这个例子本身是完全没用的;重点是并行化包含中断条件并执行 IO 操作的循环。出于这个问题的目的,我保留了通用的中断条件。
我尝试了以下方法,但程序变得非常慢(可能是因为我创建了太多任务...)。我也尝试使用 taskloop 构造,但结果几乎相同。现在,在考虑中断条件之前,我正在尝试弄清楚如何使该死的东西 运行 相当快。关于我应该如何进行的任何建议?
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
const int max_iters = 500000;
const char cmd_format[300] = "echo Iteration %d\n";
int main(int argc, char **argv) {
FILE *fp;
char ret[200];
char cmd[400];
#pragma omp parallel
#pragma omp single
for (int i = 0; i < max_iters; i++) {
#pragma omp task default(none) \
firstprivate(i,cmd,fp,ret) \
shared(cmd_format,max_iters)
{
sprintf((char *)&cmd, cmd_format, i);
fp = popen(cmd, "r");
while (!feof(fp)) {
fgets((char *)&ret, 200, fp);
if (/* some condition */) {
printf("Done\n");
i = max_iters;
}
}
pclose(fp);
}
}
return EXIT_SUCCESS;
}
我还没有测试下面的代码,但它应该仍然显示了这个想法。问题是您不能轻易中止并行计算。在 OpenMP 中执行此操作的方法是取消,请参阅 https://www.openmp.org/spec-html/5.1/openmpse28.html#x144-1560002.20。
这是使用 cancel
结构的代码:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
const int max_iters = 500000;
const char cmd_format[300] = "echo Iteration %d\n";
int main(int argc, char **argv) {
FILE *fp;
char ret[200];
char cmd[400];
#pragma omp parallel
#pragma omp single
#pragma omp taskgroup
for (int i = 0; i < max_iters; i++) {
#pragma omp task default(none) \
firstprivate(i,cmd,fp,ret) \
shared(cmd_format,max_iters)
{
sprintf((char *)&cmd, cmd_format, i);
fp = popen(cmd, "r");
while (!feof(fp)) {
fgets((char *)&ret, 200, fp);
if (/* some condition */) {
#pragma omp atomic update
i = max_iters;
printf("Done\n");
#pragma omp cancel taskgroup
}
}
pclose(fp);
}
}
return EXIT_SUCCESS;
}
在单曲之后我引入了一个 taskgroup
结构,这样现在创建的所有任务都有一个逻辑分组。一旦您的条件得到满足,cancel
构造将触发取消 taskgroup
.
的任务
需要注意的一件事是:这不是立即采取的行动。如果一个任务已经开始执行,它不会被终止,除非它到达一个取消点或者它到达它的代码区域的末尾。已生成但位于任务池中且尚未开始执行的任务将被丢弃。
因此,在使用此功能时,您需要让您的代码意识到这一点并处理这些情况。因此,例如,如果多个任务的终止条件可以为真,则需要使代码足够灵活,以便两个或多个任务可以输入 if
语句并尝试记录结果(在根据您的情况,将 i
设置为 max_iters
)。这就是为什么我添加了 atomic
构造以确保在更新 i
变量时不会发生竞争,但延迟的任务可能仍会覆盖较早任务的结果。由于您的真实代码中必须发生的事情取决于您的代码实际做了什么,我无法提供更好的建议。
我是 OpenMP 的初学者,正在学习有关任务的知识,并希望将它们应用到以下场景中。这个例子本身是完全没用的;重点是并行化包含中断条件并执行 IO 操作的循环。出于这个问题的目的,我保留了通用的中断条件。
我尝试了以下方法,但程序变得非常慢(可能是因为我创建了太多任务...)。我也尝试使用 taskloop 构造,但结果几乎相同。现在,在考虑中断条件之前,我正在尝试弄清楚如何使该死的东西 运行 相当快。关于我应该如何进行的任何建议?
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
const int max_iters = 500000;
const char cmd_format[300] = "echo Iteration %d\n";
int main(int argc, char **argv) {
FILE *fp;
char ret[200];
char cmd[400];
#pragma omp parallel
#pragma omp single
for (int i = 0; i < max_iters; i++) {
#pragma omp task default(none) \
firstprivate(i,cmd,fp,ret) \
shared(cmd_format,max_iters)
{
sprintf((char *)&cmd, cmd_format, i);
fp = popen(cmd, "r");
while (!feof(fp)) {
fgets((char *)&ret, 200, fp);
if (/* some condition */) {
printf("Done\n");
i = max_iters;
}
}
pclose(fp);
}
}
return EXIT_SUCCESS;
}
我还没有测试下面的代码,但它应该仍然显示了这个想法。问题是您不能轻易中止并行计算。在 OpenMP 中执行此操作的方法是取消,请参阅 https://www.openmp.org/spec-html/5.1/openmpse28.html#x144-1560002.20。
这是使用 cancel
结构的代码:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
const int max_iters = 500000;
const char cmd_format[300] = "echo Iteration %d\n";
int main(int argc, char **argv) {
FILE *fp;
char ret[200];
char cmd[400];
#pragma omp parallel
#pragma omp single
#pragma omp taskgroup
for (int i = 0; i < max_iters; i++) {
#pragma omp task default(none) \
firstprivate(i,cmd,fp,ret) \
shared(cmd_format,max_iters)
{
sprintf((char *)&cmd, cmd_format, i);
fp = popen(cmd, "r");
while (!feof(fp)) {
fgets((char *)&ret, 200, fp);
if (/* some condition */) {
#pragma omp atomic update
i = max_iters;
printf("Done\n");
#pragma omp cancel taskgroup
}
}
pclose(fp);
}
}
return EXIT_SUCCESS;
}
在单曲之后我引入了一个 taskgroup
结构,这样现在创建的所有任务都有一个逻辑分组。一旦您的条件得到满足,cancel
构造将触发取消 taskgroup
.
需要注意的一件事是:这不是立即采取的行动。如果一个任务已经开始执行,它不会被终止,除非它到达一个取消点或者它到达它的代码区域的末尾。已生成但位于任务池中且尚未开始执行的任务将被丢弃。
因此,在使用此功能时,您需要让您的代码意识到这一点并处理这些情况。因此,例如,如果多个任务的终止条件可以为真,则需要使代码足够灵活,以便两个或多个任务可以输入 if
语句并尝试记录结果(在根据您的情况,将 i
设置为 max_iters
)。这就是为什么我添加了 atomic
构造以确保在更新 i
变量时不会发生竞争,但延迟的任务可能仍会覆盖较早任务的结果。由于您的真实代码中必须发生的事情取决于您的代码实际做了什么,我无法提供更好的建议。