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

向新进程传递SharedMemory时触发FileNotFoundError问题排查

多进程共享Numpy数组时的WinError 2问题解决

问题背景

我开发了一个多进程应用,需要在进程间传递Numpy数组,计划通过SharedMemoryManager.SharedMemory()让数组指向同一共享内存缓冲区,并用锁避免竞态条件。

创建进程代码

buffer = self.data_manager.SharedMemory(size=(w * h * c))
queue = self.data_manager.Queue()
lock = self.data_manager.Lock()
stop_event = self.data_manager.Event()

frame_buffer = np.ndarray(
    (h, w, c),
    dtype=np.uint8,
    buffer=buffer.buf,
)

proc = Process(
    target=run_camera,
    name=camera_request.name,
    kwargs={
        "command_queue": queue,
        "lock": lock,
        "stop_event": stop_event,
        "shared_buffer": buffer,
        # 其他参数
    },
)

proc.start()

目标函数代码

def run_camera(
    command_queue: Queue[CameraCommand],
    lock: Lock,
    stop_event: Event,
    shared_buffer: shared_memory.SharedMemory,
    # 其他参数

) -> None:

    frame_buffer = np.ndarray(
        (h, w, c),
        dtype=np.uint8,
        buffer=shared_buffer.buf,
    )
    # 对数组进行操作

触发的错误

启动新进程后立即抛出以下错误:

Traceback (most recent call last): File "", line 1, in

File "C:\path\to\Miniconda3\envs\trumpf\lib\multiprocessing\spawn.py", line 116, in spawn_main
exitcode = _main(fd, parent_sentinel)

File "C:\path\to\Miniconda3\envs\trumpf\lib\multiprocessing\spawn.py", line 126, in _main
self = reduction.pickle.load(from_parent)

File "C:\path\to\Miniconda3\envs\trumpf\lib\multiprocessing\shared_memory.py", line 161, in init
h_map = _winapi.OpenFileMapping( FileNotFoundError: [WinError 2] The system cannot find the file specified: 'wnsm_3ab8096f'

特殊现象:在proc.start()行设置断点,触发后继续运行则无错误,初步判断是时序问题,但测试time.sleep()未解决。


问题原因与解决方法

核心原因

Windows系统下,SharedMemory对象依赖系统级的文件映射实现。如果父进程中创建的SharedMemory对象被Python垃圾回收机制过早回收,对应的文件映射会被提前关闭,子进程启动时就找不到目标文件映射,从而抛出错误。断点暂停时父进程执行停滞,SharedMemory对象不会被回收,因此子进程能正常连接。

具体解决方案

  1. 保留共享内存对象引用
    在父进程中,将buffer对象存入全局列表或类实例属性,避免被垃圾回收:

    # 在类初始化时添加存储属性
    self.active_shared_buffers = []
    # 创建buffer后加入列表
    self.active_shared_buffers.append(buffer)
    

    待子进程退出后,再从列表中移除并清理该对象。

  2. 传递共享内存名称而非对象
    避免直接序列化SharedMemory对象,改为传递其name属性,让子进程主动连接:

    • 修改进程创建代码:
      proc = Process(
          target=run_camera,
          name=camera_request.name,
          kwargs={
              "command_queue": queue,
              "lock": lock,
              "stop_event": stop_event,
              "shared_memory_name": buffer.name,
              "frame_shape": (h, w, c),
              "frame_dtype": np.uint8,
              # 其他参数
          },
      )
      
    • 修改目标函数:
      def run_camera(
          command_queue: Queue[CameraCommand],
          lock: Lock,
          stop_event: Event,
          shared_memory_name: str,
          frame_shape: tuple,
          frame_dtype: np.dtype,
          # 其他参数
      
      ) -> None:
          shared_buffer = shared_memory.SharedMemory(name=shared_memory_name)
          try:
              frame_buffer = np.ndarray(frame_shape, dtype=frame_dtype, buffer=shared_buffer.buf)
              # 对数组进行操作
          finally:
              # 子进程仅关闭连接,不释放共享内存,由父进程负责清理
              shared_buffer.close()
      
  3. 显式控制共享内存生命周期
    父进程需等待子进程完全退出后,再清理共享内存:

    # 等待子进程结束
    proc.join()
    # 关闭并释放共享内存
    buffer.close()
    buffer.unlink()
    # 从引用列表中移除
    self.active_shared_buffers.remove(buffer)
    

内容的提问来源于stack exchange,提问作者Roland Deschain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 09:10:28