You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:将单进程仿真代码改造为多进程并行运行

多进程仿真改造故障求助

我有一段可正常运行的仿真代码,通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 01:35:25