我想实现非常有效的并行缩减操作(即求和):二维数组的每一列(行中的内存缓冲区)应该与一维数组的条目相加。 / p>
更清楚预期的输入和输出
double* array = malloc(sizeof(double) * shape0 * shape1) /* (shape0*shape1) 2-d array */
double* out = malloc(sizeof(double) * shape1) /* where out[j] = sum_j(array_ij) */
并行化行的总和是非常简单和有效的,因为这些值在内存中是连续的,并且没有竞争条件的风险。我发现这个效果很好
void sum_rows(double* array, int shape0, int shape1, double* out) {
int i, j;
#pragma omp parallel for private(j) schedule(guided)
for (i=0; i < shape0; i++){
for (j=0; j < shape1; j++){
out[i] += array[shape1 * i + j];
}
}
}
我发现在另一个轴上进行并行化更加困难。 这应该是一个简单的平行配方,但我无法找到一个明确的答案是什么是最有效的编程方式。
这是我想编写高效并行版本的天真串行代码:
void sum_columns(double* array, int shape0, int shape1, double* out) {
int i, j;
for (i=0; i < shape0; i++){
for (j=0; j < shape1; j++){
out[j] += array[shape1 * i + j];
}
}
}
注意: 我已经阅读了以下q / a但它们并没有让我对天真的顺序代码有任何加速:
Parallelizing matrix times a vector by columns and by rows with OpenMP
答案 0 :(得分:1)
报告一些尝试后我能够实现的更快的实现。在这里,我将列分配给不同的线程,以这种方式尽可能在本地工作并避免错误共享。
void sum_columns(double* array, int N_rows, int N_cols, double* out, int n_threads) {
omp_set_dynamic(0);
omp_set_num_threads(n_threads);
#pragma omp parallel
{
/* private vars */
int i, j, id, N_threads, col_chunk_size, start_col, end_col;
/* ICVs */
id = omp_get_thread_num();
N_threads = omp_get_num_threads();
/* distribute cols to different threads */
col_chunk_size = N_cols / N_threads;
start_col = id * col_chunk_size;
end_col = (id+1) * col_chunk_size;
if (id == N_threads - 1) end_col = N_cols;
/* main loop */
for (i=0; i < N_rows; i++){
for (j=start_col; j < end_col; j++){
out[j] += array[N_cols * i + j];
}
}
}
}