我想使用OpenMP来并行化我的代码,但我不确定我的循环如何保持其属性。
我知道内循环生成结果的次数,以及它有多大:
(取决于宽度的均匀性,内环表现不同,因此天花板和地板分区)
const size_t
bytes_per_result = <something>,
totalloops = width/2 * iceildiv(width, 2);
所以我可以将每个结果写入文件中的已知位置。为此,我只需分配一个大小的文件,然后将其倒回到开头:
FILE* f = fopen(<somefile>, "w");
fseek(f, totalloops * bytes_per_result - 1, SEEK_SET); //seek to before file end
fputc('\0', f); //write byte to allocate whole file
rewind(f);
然后我循环,并计算内部循环通过k
运行的数字。在最后一个循环之后,k == totalloops
。
result_t result;
size_t i, j, k;
for (i=0, k=0; i<width; i++) {
for (j=0; j<imin(i, width-i-1); j++, k++) {
result = do_calculation(i, j);
fseek(f, k * bytes_per_result, SEEK_SET);
fwrite_result(f, result);
}
}
现在我该如何并行化?并行化的东西当然是do_calculation
部分,而寻求和写作必须一起声明#pragma omp critical
。但是我如何使k
表现得像我想要的那样?
OpenMP只能解析简单的for循环,最后只有一个增量表达式,而不是两个,所以我不能保留k++
...
答案 0 :(得分:0)
你可以分2步完成:
result_t buffer[MAXLEN];
#pragma omp prarellel for
for (size_t i=0; i<width; i++) {
for (size_t j=0; j<imin(i, width-i+1); j++) {
result_t result = do_calculation(i, j);
size_t k=.....;
buffer[k]=result;
}
}
fwrite_buffer(f, buffer, total_length);
由于结果日期很大(~10GB),您可能会花费大部分时间将数据写入磁盘。但是,多线程代码通常无法提高磁盘带宽限制任务的性能。你应该重新考虑多线程是否适合你的任务。
如果缓冲区大小有问题,您可以保留原始设计,并使用omp critical
来避免文件访问时的竞争条件。
#pragma omp prarellel for schedule(dynamic,3)
for (size_t i=0; i<width; i++) {
result_t buffer[MAXLEN];
for (size_t j=0; j<imin(i, width-i+1); j++) {
result_t result = do_calculation(i, j);
size_t k=ijw2k(i,j,width);
#pragma omp critical {
fseek(f, k * bytes_per_result, SEEK_SET);
fwrite_buffer(f, result);
}
}
}
根据您的代码,计算k
似乎有点复杂,但仍然可行。 k
只是i, j, width
的函数,我认为这不应该是你的问题。
size_t ijw2k(size_t i, size_t j, size_t width) {
size_t k;
if (width % 2) {
if (i<width-i+1) {
....
} else {
....
}
} else {
if (i<width-i+1) {
....
} else {
....
}
}
return k;
}