我有一个生成数据的大循环.每次迭代需要1秒钟,然后产生一大块数据.我需要以正确的顺序写入文件的所有块.
如果我只想并行化循环,我可以写这样的东西(高度简化):
FILE* f = fopen("output.txt", "w");
omp_lock_t lock;
omp_init_lock(&lock);
int nIterations = 1000000;
#pragma omp parallel for
for(int thread=0; thread<4; thread++)
{
int a=0, b=0, c=0;
for(int n=thread; n<nIterations; n+=4)
{
int value = do_computations(&a, &b, &c);
omp_set_lock(&lock);
fprintf(f, "%d\n", value);
omp_unset_lock(&lock);
}
}
#pragma omp barrier
fclose(f);
omp_destroy_lock(&lock);
Run Code Online (Sandbox Code Playgroud)
这会将我的输出输入到文件中,但不保证条目的顺序.
我想同步执行,以便所有线程完成他们的任务,然后主线程写入文件,然后线程恢复.换句话说,我想要这样的事情:
#pragma omp parallel for
for(int thread=0; thread<4; thread++)
{
int a=0, b=0, c=0;
int values[4];
for(int n=thread; n<nIterations; n+=4)
{
values[n] = do_computations(&a, &b, &c);
#pragma omp barrier
if(thread == 0)
{
for(int i=0; i<4; i++)
fprintf(f, "%d\n", values[i]);
}
#pragma omp barrier
}
}
#pragma omp barrier
Run Code Online (Sandbox Code Playgroud)
除了一些莫名其妙的原因,这是OpenMP规范禁止的.
或者我可以试试
#pragma omp parallel for
for(int thread=0; thread<4; thread++)
{
int a=0, b=0, c=0;
for(int n=thread; n<nIterations; n+=4)
{
int value = do_computations(&a, &b, &c);
#pragma omp ordered
{
fprintf(f, "%d\n", value);
}
}
}
#pragma omp barrier
fclose(f);
Run Code Online (Sandbox Code Playgroud)
但这也不会起作用,因为"带有for构造的循环的迭代......不能执行多个有序指令."
我不想将代码重写为单个循环,我不想交换循环.
有没有一种干净的方法来使用OpenMP,没有其他线程/同步工具?
你正在尝试做两件事——计算和 IO。计算可以并行,但IO必须是串行的。但是,通过将 IO 放在与计算相同的循环中,您也会强制计算序列化,这是没有意义的。
你最好先完成所有计算,然后再进行 IO。即使是串行方式,这几乎肯定会更快,特别是如果您可以将数据以二进制形式写入一大块,而不是通过 fprintfs 进行循环。
FILE* f = fopen("output.txt", "w");
const int nIterations = 1000000;
int values[nIterations];
#pragma omp parallel for
for(int n=0; n<niterations; n++)
{
int a=0, b=0, c=0;
values[n] = do_computations(&a, &b, &c);
}
for (int n=0; n<niterations; n++)
fprintf(f,"%d\n", values[n]);
fclose(f);
Run Code Online (Sandbox Code Playgroud)
当然,这需要更多的内存,但速度与内存是一个常见的权衡。如果这种权衡的极端不起作用,您始终可以以可调整大小的块进行计算:
const int nIterations = 1000000;
const int chunkSize = 10000;
int values[chunkSize];
int chunkNum = 0;
int chunkLeft = chunkSize;
for (int start = 0; start < nIterations; start+= chunkSize) {
if (start+chunkSize > nIterations) chunkLeft = nIterations - start;
#pragma omp parallel for
for(int n=start; n<start+chunkLeft; n++)
{
int a=0, b=0, c=0;
values[n-start] = do_computations(&a, &b, &c);
}
for (int n=0; n<chunkLeft; n++)
fprintf(f,"%d\n", values[n]);
}
fclose(f);
Run Code Online (Sandbox Code Playgroud)