[英]C OpenMP parallel for loops make it much slower than single thread
我是C语言中的OpenMP的新手。我使用它来并行执行函数中的for循环,但与单线程情况相比,它大大降低了我的for循环。 例如,对于每个点(光晕),for循环可以完成10s左右,但是使用OpenMP则需要花费几分钟。
在此函数中,我试图通过计算壳内的每个粒子的密度(晕圈)来计算许多壳的密度,然后将它们精炼成一个数组。 有512 ^ 3个粒子,大约要计算200个点(晕)。 我想为不同的线程拆分点(晕)以使其更快。
#define ArrayAccess2D_n2(a, n1, n2, i1, i2) (a)[ i2+n2*i1 ]
void halo_shell_rho(float boxsize, float *halo_pos, float *halo_R, int halo_number,\
int halo_start, int halo_end, float *par_pos, long long par_number,\
int shell_bins, float rmax_fac, float *out_shell_den){
float temp;
long long iter_sfs=0, iter_sfc=0, iter_ufs=0, iter_ufc=0;
int dim=3;
float par_posx, par_posy, par_posz, dist;
float halo_posx, halo_posy, halo_posz, halo_rad;
int i=0, ini_j=0, vol_j=0;
int a=0, b=0;
long long k=0;
#pragma omp parallel for private(i, ini_j, vol_j, a, b, k)
for(i=halo_start; i<=halo_end; i++){
printf("halo %d\n", i);
float count[shell_bins];
float volume[shell_bins];
for(ini_j=0; ini_j<shell_bins; ini_j++){
count[ini_j] = 0;
volume[ini_j] = 0; }
halo_posx = ArrayAccess2D_n2(halo_pos, dim, halo_number, 0, i);
halo_posy = ArrayAccess2D_n2(halo_pos, dim, halo_number, 1, i);
halo_posz = ArrayAccess2D_n2(halo_pos, dim, halo_number, 2, i);
halo_rad = halo_R[i];
for(vol_j=0; vol_j<shell_bins; vol_j++){
volume[vol_j] = shell_volume((vol_j+1)*halo_rad*rmax_fac/(shell_bins*1000), vol_j*halo_rad*rmax_fac/(shell_bins*1000)); }
for(k=0; k<par_number; k++){
par_posx = ArrayAccess2D_n2(par_pos, par_number, dim, k, 0);
par_posy = ArrayAccess2D_n2(par_pos, par_number, dim, k, 1);
par_posz = ArrayAccess2D_n2(par_pos, par_number, dim, k, 2);
dist = pb_distance(boxsize*1000, halo_posx, halo_posy, halo_posz, par_posx, par_posy, par_posz); //1000 for boxsize in Mpc
if(dist <= 2*rmax_fac*halo_rad){
for(a=0; a<shell_bins; a++){
if((dist <= halo_rad*(a+1)*rmax_fac/shell_bins) && (dist >= halo_rad*a*rmax_fac/shell_bins)){
count[a] += 1; }
}
}
}
for(b=0; b<shell_bins; b++){
out_shell_den[(i-halo_start+0*(1+halo_end-halo_start))*shell_bins+b] = count[b]/volume[b];
//out_shell_den has shape (2, halo_number, shell_bins), 0 for edge, 1 for density
out_shell_den[(i-halo_start+1*(1+halo_end-halo_start))*shell_bins+b] = (2*b+1)*rmax_fac/(shell_bins*2);
}
}
}
有人可以帮我吗? 我知道这是一个非常常见的问题,但我没有从其他帖子中找到任何解决方案。 如果有帮助,我可以在具有32个线程的群集上运行它。
谢谢!
感谢@DavidSchwartz和@ tim18。
像halo_rad和par_posx这样的变量在并行操作之前声明,这意味着它们被隐式假定为公共的。 因此它放慢了速度,因为所有线程都在争夺使用它们的权利。 解决此问题的一种方法是将所有变量添加到private()。 但是我认为更好的方法是像这样在并行内部声明变量:
void halo_shell_rho(float boxsize, float *halo_pos, float *halo_R, int halo_number, int halo_start, int halo_end, float *par_pos, long long par_number, int shell_bins, float rmax_fac, float *out_shell_den){
int dim=3;
int i=0, ini_j=0, vol_j=0, a=0, b=0;
long long k=0;
#pragma omp parallel for private(i, ini_j, vol_j, a, b, k)
for(i=halo_start; i<=halo_end; i++){
printf("halo %d\n", i);
float halo_posx, halo_posy, halo_posz, halo_rad;
float count[shell_bins];
float volume[shell_bins];
for(ini_j=0; ini_j<shell_bins; ini_j++){
count[ini_j] = 0;
volume[ini_j] = 0; }
halo_posx = ArrayAccess2D_n2(halo_pos, dim, halo_number, 0, i);
halo_posy = ArrayAccess2D_n2(halo_pos, dim, halo_number, 1, i);
halo_posz = ArrayAccess2D_n2(halo_pos, dim, halo_number, 2, i);
halo_rad = halo_R[i];
for(vol_j=0; vol_j<shell_bins; vol_j++){
volume[vol_j] = shell_volume((vol_j+1)*halo_rad*rmax_fac/(shell_bins*1000), vol_j*halo_rad*rmax_fac/(shell_bins*1000)); }
for(k=0; k<par_number; k++){
float par_posx, par_posy, par_posz, dist;
par_posx = ArrayAccess2D_n2(par_pos, par_number, dim, k, 0);
par_posy = ArrayAccess2D_n2(par_pos, par_number, dim, k, 1);
par_posz = ArrayAccess2D_n2(par_pos, par_number, dim, k, 2);
dist = pb_distance(boxsize*1000, halo_posx, halo_posy, halo_posz, par_posx, par_posy, par_posz); //1000 for boxsize in Mpc
if(dist <= 2*rmax_fac*halo_rad){
for(a=0; a<shell_bins; a++){
if((dist <= halo_rad*(a+1)*rmax_fac/shell_bins) && (dist >= halo_rad*a*rmax_fac/shell_bins)){
count[a] += 1; }
}
}
}
for(b=0; b<shell_bins; b++){
out_shell_den[(i-halo_start+0*(1+halo_end-halo_start))*shell_bins+b] = count[b]/volume[b]; //out_shell_den has shape (2, halo_number, shell_bins), 0 for edge, 1 for density
out_shell_den[(i-halo_start+1*(1+halo_end-halo_start))*shell_bins+b] = (2*b+1)*rmax_fac/(shell_bins*2);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.