以前的帖子如下:
我正在尝试运行一个按顺序运行良好的 CFD(计算流体动力学)代码,但我想通过对其进行并行化来加快速度。 (对于因此感兴趣,我们正在计算 3 维的传热)。 更准确地说,我必须并行放置一个 3 和 4 的嵌套循环。根据我的了解,我的代码受 CPU 限制,所以我必须使用多处理而不是线程,到目前为止我对吗? 我已经尝试了几种方法来做到这一点,甚至是线程以防万一。 实际上,我无法完成计算,每次尝试时我的笔记本电脑都冻结了,但是代码已编译并执行...我有一个带有 Intel® Core™ i7-6500U CPU @ 2.50GHz 的 Toshiba Satellite × 4、1,0 TB 和 3.7 GiB,在 ubuntu 20.04 LTS 上。
第一次测试:
import multiprocessing as mp
def iterative(i,j,k):
ind = j*(N+2)+i+k*((N+1)*(N+2)+N+2)
indW = ind-1
indE = ind+1
indN = ind + (N+2)
indS = ind - (N+2)
indT = ind + ((N+1)*(N+2)+N+2)
indB = ind - ((N+1)*(N+2)+N+2)
if j == 0 and k != 0 and k != N+1:
T[ind] = T_F
elif i == N+1 and j != N+1 and k != N+1 and k != 0:
T[ind] = T_R
elif i == 0 and j != 0 and k != 0 and k != N+1:
T[ind] = T_L
elif i != 0 and j == N+1 and k != 0 and k != N+1:
T[ind] = T_B
elif k == N+1:
T[ind] = T_U
elif k == 0:
T[ind] = T_D
elif i == N and j == N and k == N:
T[ind] = T[ind] * (1-9*c) + T_R * (2*c) + T[indW]*c + T_B *(2*c) + c*T[indS] + 2*c*T_U + c*T[indB] + s*dt
elif i == 1 and j == N and k == N:
T[ind] = T[ind] * (1-9*c) + T_L * (2*c) + c*T[indE] + 2*c*T_B + c*T[indS] + 2*c*T_U + c*T[indB] + s*dt
elif i == N and j == N and k == 1:
T[ind] = T[ind] * (1-9*c) + 2*c*T_R + c*T[indW] + 2*c*T_B + c*T[indS] + 2*c*T_D + c*T[indT] + s*dt
elif i == 1 and j == N and k == 1:
T[ind] = T[ind] * (1-9*c) + 2*c*T_L + c*T[indE] + 2*c*T_B + c*T[indS] + 2*c*T_D + c*T[indT] + s*dt
elif i != 0 and i != N+1 and j == 1 and k == N:
T[ind] = T[ind] * (1-8*c) + c*T[indE] + c*T[indW] + c*T[indN] + 2*c*T_F + 2*c*T_U + c*T[indB] + s*dt
...
...
processes = []
for n in range(0,8):
for i in range(0,N+2):
for j in range(0,N+2):
for k in range(0,N+2):
p = mp.Process(target=iterative,(i,j,k))
p.start()
Processes.append(p)
for p in processes:
p.join()
....
....
为什么会死机/崩溃?
我也尝试制作这样的 ProcessPool:
pool = multiprocessing.Pool(multiprocessing.cpu_count())
for n in range(0,N+2):
for i in range(0,N+2):
for j in range(0,N+2):
for k in range(0,N+2):
pool.apply_async(initial,(i,j,k))
......
......
同样的事情,它崩溃了......
使用 Thread,它不会崩溃,但是计算需要大约 600 秒,而顺序大约为 1 分钟……我认为这是因为我的代码受 CPU 限制(而不是 I/O 限制)并且它需要时间来设置所有线程......我说得对吗? 所以,我也用 Process 而不是线程来做到这一点,但同样,它崩溃了...... 好吧,我不知道如何使它正常工作而不会使我的笔记本电脑崩溃,这不是先验的垃圾。 有人可以帮我做这个吗?感谢您抽出宝贵时间。
在下面编辑:
正如@Jerôme Richard 在评论中向我建议的那样,我通过增加并行执行的一项任务中的操作数(增加粒度)来减少每个单元格创建的任务。这大大提高了计算速度。多线程计算的结果很好,并且比顺序计算快一点,但这种方式不是真正的并行化方式。所以我想使用多核的多处理来获得最大的计算时间。为了减少进程之间的时间通信,我想按顺序计算“初始”函数,因为这项工作非常快,而且只有迭代循环是并行的。因此,通过所有这些更改,我的笔记本电脑不再崩溃并且计算速度更快,但是通过多处理,并行迭代循环似乎不起作用,因为结果仍然是初始化的结果。我尝试使用和不使用进程池,但它返回相同的内容。不知道问题出在哪里,也许有人能看到?
以下是我的部分代码更改,首先是进程池:
import multiprocessing as mp
...
...
def iterative(i):
for j in range(0,N+2):
for k in range(0,N+2):
ind = j*(N+2)+i+k*((N+1)*(N+2)+N+2)
indW = ind-1
indE = ind+1
indN = ind + (N+2)
indS = ind - (N+2)
indT = ind + ((N+1)*(N+2)+N+2)
indB = ind - ((N+1)*(N+2)+N+2)
if j == 0 and k != 0 and k != N+1:
T[ind] = T_F
elif i == N+1 and j != N+1 and k != N+1 and k != 0:
T[ind] = T_R
elif i == 0 and j != 0 and k != 0 and k != N+1:
T[ind] = T_L
elif i != 0 and j == N+1 and k != 0 and k != N+1:
T[ind] = T_B
elif k == N+1:
T[ind] = T_U
elif k == 0:
T[ind] = T_D
elif i == N and j == N and k == N:
T[ind] = T[ind] * (1-9*c) + T_R * (2*c) + T[indW]*c + T_B *(2*c) + c*T[indS] + 2*c*T_U + c*T[indB] + s*dt
...
...
pool2 = mp.Pool(mp.cpu_count())
for n in range(0,8): # time iterative loop
print(n)
for i in range(0,N+2):
pool2.apply_async(iterative,[i])
if n == 7:
with open("chaleur_para.txt","w") as file:
for i in range(0,(N+2)**3):
file.write(str(T[i]) + "\n")
file.close()
im = plt.contourf(X,Z,M.T,100,cmap='plasma')
text = ['t = ' + str(n*dt) + ' s']
plt.legend(text,loc='upper left')
ims.append(im.collections)
if n == 7:
print("No more iteration.")
pool2.close()
pool2.join()
ani = animation.ArtistAnimation(fig, ims, interval = 1000, blit=True)
print(f"Exectuion time is {time.time()-t1} seconds.")
plt.xlabel('x')
plt.ylabel('z')
plt.xlim(-0.05,1.05)
plt.ylim(-0.05,1.05)
plt.colorbar(label='Température en °K')
ani.save("Evolution_T_2D.mp4")
plt.show()
没有游泳池:
import multiprocessing as mp
...
...
Processes = []
for n in range(0,8): # time iterative loop
print(n)
for i in range(0,N+2):
p = mp.Process(target=iterative,args=[i])
p.start()
Processes.append(p)
for p in Processes:
p.join()
if n == 7:
with open("chaleur_para.txt","w") as file:
for i in range(0,(N+2)**3):
file.write(str(T[i]) + "\n")
file.close()
im = plt.contourf(X,Z,M.T,100,cmap='plasma')
text = ['t = ' + str(n*dt) + ' s']
plt.legend(text,loc='upper left')
ims.append(im.collections)
if n == 7:
print("No more iteration.")
....
....
有人有想法吗?提前致谢。