env_manager.py — EnvManager 使用子进程模式管理仿真器的生命周期¶
文件路径:
verl/experimental/vla/workers/env/env_manager.py模块路径:verl.experimental.vla.workers.env.env_manager
文件概述¶
EnvManager 使用子进程模式管理仿真器的生命周期。它通过命令/结果队列与仿真器子进程通信,支持 NUMA 亲和性绑定和代理模式的方法调用。
核心设计¶
为什么用子进程?¶
机器人仿真器(如 MuJoCo、Isaac Sim)通常: 1. 有全局状态,不能在同一进程中运行多个实例 2. 可能不是线程安全的 3. 可能需要特定的 CPU 核心绑定(NUMA)
因此需要在独立子进程中运行。
架构¶
关键代码¶
启动仿真器¶
class EnvManager:
def __init__(self, config, rank, world_size, env_cls):
self.config = config
self.env_cls = env_cls
self.command_queue = mp.Queue()
self.result_queue = mp.Queue()
def start_simulator(self):
"""在子进程中启动仿真器"""
self.process = mp.Process(
target=self._simulator_worker,
args=(self.command_queue, self.result_queue, self.config, self.env_cls)
)
self.process.start()
# 可选:绑定到特定 NUMA 节点
if self.config.get("numa_affinity"):
self._set_numa_affinity(self.process.pid)
子进程主循环¶
@staticmethod
def _simulator_worker(command_queue, result_queue, config, env_cls):
"""仿真器子进程的主循环"""
# 创建环境实例
env = env_cls(config, ...)
while True:
# 等待命令
command, args, kwargs = command_queue.get()
if command == "shutdown":
break
# 执行命令并返回结果
method = getattr(env, command)
result = method(*args, **kwargs)
result_queue.put(result)
代理模式调用¶
def __getattr__(self, name):
"""代理模式:将方法调用转发给子进程
使用方式:
manager.chunk_step(actions)
# 实际上通过队列发送给子进程执行
"""
def proxy_method(*args, **kwargs):
self.command_queue.put((name, args, kwargs))
result = self.result_queue.get()
return result
return proxy_method
这种代理模式使得 EnvManager 可以像直接操作环境一样被使用:
NUMA 亲和性¶
def _set_numa_affinity(self, pid):
"""将子进程绑定到特定的 NUMA 节点
在多 CPU 服务器上,绑定仿真器到与 GPU
同一 NUMA 节点的 CPU 核心可以减少内存延迟。
"""
import os
os.sched_setaffinity(pid, self.numa_cores)
核心类/函数列表¶
| 名称 | 类型 | 说明 |
|---|---|---|
EnvManager |
类 | 子进程仿真器管理器 |
start_simulator |
方法 | 启动仿真器子进程 |
_simulator_worker |
静态方法 | 子进程主循环 |
__getattr__ |
方法 | 代理模式方法转发 |
_set_numa_affinity |
方法 | NUMA 核心绑定 |
与其他模块的关系¶
- 被
EnvWorker(env_worker.py)创建和使用 - 管理
LiberoEnv或IsaacEnv的子进程实例
小结¶
EnvManager 通过进程间通信(队列)隔离了仿真器的运行环境。代理模式让调用者不需要感知子进程的存在。NUMA 亲和性优化确保了在大规模服务器上的性能。