求助:将单进程仿真代码改造为多进程并行运行
多进程仿真改造故障求助
我有一段可正常运行的仿真代码,通过while True循环执行仿真逻辑,搭配for循环完成数据保存与定时重启操作。现在想把它改成多进程版本,实现4个仿真任务同时运行。我已经把核心代码封装成函数并调用多进程,但改造后的代码无法正常工作。以下是可正常运行的单进程代码和我尝试改造的多进程代码,求技术帮助:
可正常运行的单进程代码
for z in range(8): for q in range(100): time_re = time_re + 3000 tk.after(time_re,appender) tk.after(time_re,restart) ava(avaR1) while True: time_steps = range(0,iterations+1) B = Beta.get() G = Gamma.get() D = Diff.get() M = Mor.get() steps_x_or_y = np.random.rand(n) steps_x = steps_x_or_y < D/2 steps_y = (steps_x_or_y > D/2) & (steps_x_or_y < D) nx = (x + np.sign(np.random.randn(n)) * steps_x) % l ny = (y + np.sign(np.random.randn(n)) * steps_y) % l for i in np.where( (S==1) & ( np.random.rand(n) < B ))[0]: # loop over infecting agents S[(x==x[i]) & (y==y[i]) & (S==0)] = 1 # 易感者与感染者接触后被感染 S[ (S==1) & (np.random.rand(n) < G) ] = 2 # 康复 S[ (S==1) & (np.random.rand(n) < M) ] = 3 # 死亡 nrInf1 = sum(S==1) nrSus.append(sum(S==0)) nrInf.append(sum(S==1)) nrRec.append(sum(S==2)) nrRec1 = sum(S==2) nrDea = sum(S == 3) iterations += 1 tk.update() tk.title('Infected:' + str(np.sum(S==1))) x = nx # 更新x坐标 y = ny # 更新y坐标
尝试改造的多进程代码
def main1(i): # 系统物理参数 x = np.floor(np.random.rand(n)*l) # x坐标 y = np.floor(np.random.rand(n)*l) # y坐标 S = np.zeros(n) # 状态数组,0:易感, 1:感染, 2:康复 I = np.argsort((x-l/2)**2 + (y-l/2)**2) S[I[1:initial_infected]] = 1 # 感染中心附近的个体 nrRec1 = 0 nrDea = [] time_re = 0 particles = [] R = .5 # 个体绘制半径 nx = x # 更新后的x ny = y # 更新后的y def restart(): global S I = np.argsort((x-l/2)**2 + (y-l/2)**2) S = np.zeros(n) S[I[1:initial_infected]] = 1 rest = Button(tk, text='Restart',command= restart) rest.place(relx=0.05, rely=.85, relheight= 0.12, relwidth= 0.15 ) def ava(k,o): global b k.append(sum(o)/3) Beta.set(b) # 设置死亡率滑块参数 b += 0.03125 #bSaver.append(b) def appender(o): nrDea1.append(nrDea) o.append(nrRec1) for j in range(n): # 在画布生成动画粒子 particles.append( canvas.create_oval( (x[j] )*res/l, (y[j] )*res/l, (x[j]+2*R )*res/l, (y[j]+2*R )*res/l, outline=ccolor[0], fill=ccolor[0]) ) if i == 1: b=0 for z in range(3): for q in range(3): time_re = time_re + 1000 tk.after(time_re,appender(nrSRec1)) tk.after(time_re,restart) tk.after(9000,ava(avaR1,nrSRec1)) elif i == 2: b=0.25 for z in range(3): for q in range(3): time_re = time_re + 1000 tk.after(time_re,appender(nrSRec2)) tk.after(time_re,restart) tk.after(9000,ava(avaR2,nrSRec2)) elif i == 3: b=.50 for z in range(3): for q in range(3): time_re = time_re + 1000 tk.after(time_re,appender(nrSRec3)) tk.after(time_re,restart) tk.after(9000,ava(avaR3,nrSRec3)) else: b=.75 for z in range(3): for q in range(3): time_re = time_re + 1000 tk.after(time_re,appender(nrSRec4)) tk.after(time_re,restart) tk.after(9000,ava(avaR4,nrSRec4)) while True: B = Beta.get() G = Gamma.get() D = Diff.get() steps_x_or_y = np.random.rand(n) steps_x = steps_x_or_y < D/2 steps_y = (steps_x_or_y > D/2) & (steps_x_or_y < D) nx = (x + np.sign(np.random.randn(n)) * steps_x) % l ny = (y + np.sign(np.random.randn(n)) * steps_y) % l for i in np.where( (S==1) & ( np.random.rand(n) < B ))[0]: # 遍历感染者 S[(x==x[i]) & (y==y[i]) & (S==0)] = 1 # 易感者与感染者接触后被感染 S[ (S==1) & (np.random.rand(n) < G) ] = 2 # 康复 nrDea= sum(S == 3) nrRec1 = sum(S==2) tk.update() tk.title('Infected:' + str(np.sum(S==1))) x = nx # 更新x坐标 y = ny # 更新y坐标 if __name__ == '__main__': p1=mp.Process(target=main1, args=(1,)) p1.start() p2=mp.Process(target=main1, args=(2,)) p2.start() p3=mp.Process(target=main1, args=(3,)) p3.start() p4=mp.Process(target=main1, args=(4,)) p4.start() joinedList = avaR1+avaR2+avaR3+avaR4 print(joinedList) Tk.mainloop(canvas)
核心问题与修复方案
- Tkinter跨进程冲突:Tkinter是单线程单进程GUI库,不能在子进程中操作主进程的
tk、canvas等控件。每个子进程必须创建独立的Tk实例,完全隔离GUI资源。 - 进程间数据共享失效:多进程内存空间完全隔离,
avaR1、nrSRec1等列表无法直接跨进程访问,需用multiprocessing.Queue或Manager实现数据传递。 - 无限循环阻塞事件循环:子进程中的
while True会卡死Tk事件循环,应改用tk.after()驱动仿真步骤,让GUI事件正常处理。 - 未定义变量报错:
nrDea1、ccolor、res等变量未在函数内定义,需补充初始化或改为局部变量。 - 主进程
mainloop调用错误:Tk.mainloop(canvas)写法错误,每个子进程的Tk实例需自行调用mainloop(),主进程负责收集结果即可。
修复后代码框架示例
import multiprocessing as mp import tkinter as tk import numpy as np def run_simulation(process_id, result_queue): # 每个进程创建独立的Tk实例 root = tk.Tk() root.title(f"仿真任务 {process_id}") # 初始化仿真参数 n = 1000 l = 50 initial_infected = 10 x = np.floor(np.random.rand(n)*l) y = np.floor(np.random.rand(n)*l) S = np.zeros(n) I = np.argsort((x-l/2)**2 + (y-l/2)**2) S[I[1:initial_infected]] = 1 # 创建独立控件 canvas = tk.Canvas(root, width=500, height=500) canvas.pack() Beta = tk.DoubleVar(value=0 if process_id==1 else 0.25 if process_id==2 else 0.5 if process_id==3 else 0.75) beta_slider = tk.Scale(root, variable=Beta, from_=0, to=1, label="感染率") beta_slider.pack() # 进程内数据存储 ava_data = [] nr_records = [] def restart(): nonlocal S, x, y x = np.floor(np.random.rand(n)*l) y = np.floor(np.random.rand(n)*l) S = np.zeros(n) I = np.argsort((x-l/2)**2 + (y-l/2)**2) S[I[1:initial_infected]] = 1 def appender(): nonlocal nr_records nr_records.append(sum(S==2)) def ava(): nonlocal ava_data, Beta if nr_records: ava_data.append(sum(nr_records[-3:])/3) current_beta = Beta.get() Beta.set(min(current_beta + 0.03125, 1)) # 设置定时任务 time_re = 0 for z in range(3): for q in range(3): time_re += 1000 root.after(time_re, appender) root.after(time_re, restart) root.after(time_re + 6000, ava) def simulation_step(): nonlocal x, y, S B = Beta.get() G = 0.1 # 可替换为滑块控件 D = 0.5 # 可替换为滑块控件 steps_x_or_y = np.random.rand(n) steps_x = steps_x_or_y < D/2 steps_y = (steps_x_or_y > D/2) & (steps_x_or_y < D) nx = (x + np.sign(np.random.randn(n)) * steps_x) % l ny = (y + np.sign(np.random.randn(n)) * steps_y) % l # 感染逻辑 infect_indices = np.where((S==1) & (np.random.rand(n) < B))[0] for i in infect_indices: S[(x==x[i]) & (y==y[i]) & (S==0)] = 1 # 康复逻辑 S[(S==1) & (np.random.rand(n) < G)] = 2 x = nx y = ny # 更新GUI标题 root.title(f"仿真任务 {process_id} | 感染者: {sum(S==1)}") # 循环执行下一个仿真步骤 root.after(100, simulation_step) # 启动仿真循环 simulation_step() # 关闭窗口时传递数据到主进程 def on_close(): result_queue.put((process_id, ava_data)) root.destroy() root.protocol("WM_DELETE_WINDOW", on_close) root.mainloop() if __name__ == '__main__': result_queue = mp.Queue() processes = [] for i in range(1,5): p = mp.Process(target=run_simulation, args=(i, result_queue)) processes.append(p) p.start() # 收集所有进程结果 results = [] for _ in range(4): results.append(result_queue.get()) # 等待进程结束 for p in processes: p.join() # 合并并打印结果 joined_list = [] for pid, data in sorted(results): joined_list.extend(data) print(joined_list)
内容的提问来源于stack exchange,提问作者MichealTheMagic
相关产品推荐
相关产品推荐

