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

如何并行运行多个带独立进程的simpy.Environment仿真环境

Simpy多仿真环境并行运行实现方案

问题根因

simpy.Environment本身是单线程驱动的事件循环模型,直接在主程序里用for循环挨个实例化、调用env.run()时,单个环境的事件循环会一直占住当前线程的执行权,直到仿真完全结束才会返回,本质就是串行执行,自然会阻塞其他环境启动。

可行实现方案

最适配DRL训练采样场景的方案是多进程隔离运行,不要用多线程(受Python GIL限制,CPU密集的仿真逻辑无法真正并行,额外开销大),具体实现逻辑如下:

  • 每个simpy.Environment实例完全在独立的子进程内初始化、运行,不同进程的内存空间完全隔离,事件循环互不干扰,可被操作系统调度到不同CPU核心实现真正并行
  • 进程间通过队列传递DRL交互需要的控制指令、观测、动作、奖励、结束标志等数据
  • 可以自己实现进程通信逻辑,也可以直接复用现有DRL框架的并行环境封装,减少重复代码

最简实现参考

import simpy
from multiprocessing import Process, Queue

# 以下两个函数替换成你自己的仿真逻辑
def reset_env(env, config):
    """重置仿真环境,返回初始观测"""
    # 清空原有进程,重新绑定仿真实体、自定义进程
    pass

def step_env(env, action, step_duration=1):
    """执行动作,步进仿真step_duration时长,返回(观测, 奖励, 结束标志)"""
    # 把动作写入仿真对应实体的状态,驱动env运行step_duration时长
    # 统计奖励、判断是否触发终止条件
    pass

def env_worker(config, action_q, obs_q, seed):
    """子进程内运行的单仿真环境工作逻辑"""
    # 子进程内部独立初始化simpy环境,避免跨进程传环境对象
    env = simpy.Environment()
    env._seed = seed
    # 初始化自定义仿真进程
    while True:
        cmd, data = action_q.get()
        if cmd == "reset":
            obs = reset_env(env, config)
            obs_q.put(obs)
        elif cmd == "step":
            obs, reward, done = step_env(env, data)
            obs_q.put((obs, reward, done))
        elif cmd == "close":
            break

if __name__ == "__main__":
    PARALLEL_ENV_NUM = 8  # 建议和CPU核心数匹配
    base_config = {}  # 你的仿真统一配置
    action_queues, obs_queues, procs = [], [], []
    
    # 启动所有并行环境子进程
    for env_idx in range(PARALLEL_ENV_NUM):
        act_q, ob_q = Queue(), Queue()
        p = Process(target=env_worker, args=(base_config, act_q, ob_q, env_idx))
        p.start()
        procs.append(p)
        action_queues.append(act_q)
        obs_queues.append(ob_q)
    
    # DRL训练循环逻辑示例
    # 给所有环境发重置指令
    for aq in action_queues:
        aq.put(("reset", None))
    init_obs_list = [oq.get() for oq in obs_queues]
    
    # 训练时批量发动作、收结果即可,所有环境在子进程内并行运行
    # 训练结束后记得关闭所有子进程
    for aq in action_queues:
        aq.put(("close", None))
    for p in procs:
        p.join()

注意事项

  • 不要尝试在单进程内轮询调度多个simpy环境的事件循环(比如每次让每个env跑1个仿真步长再切换),本质还是串行执行,调度开销远大于收益
  • 所有仿真相关的自定义类、函数要支持序列化,不要把无法序列化的对象(打开的文件句柄、线程锁、数据库连接等)从主进程传到子进程,这类资源要在子进程内部初始化
  • 每个并行环境要设置独立的随机种子,避免采样轨迹相关性过高,影响on-policy DRL算法的收敛效果
  • 如果用Stable Baselines3等现成DRL框架,只需要把单simpy环境封装成标准Gym接口,直接调用框架自带的SubprocVecEnv即可自动完成多进程并行封装,不需要自己写进程通信逻辑

内容的提问来源于stack exchange,提问作者amin zak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:01:46