Python3 multiprocessing SharedMemory 重连已有共享内存失败问题
问题描述
我想实现的操作是:先运行testb.py创建共享内存,再运行testc.py连接该共享内存;关闭testc.py后重新运行,再次连接共享内存,但最后一步遇到问题。简单来说,我希望在长生命周期的代码中创建共享内存,供不同进程连接,但进程结束重启后出现异常。
相关代码
testa.py
from multiprocessing.shared_memory import SharedMemory class CommonDataHandler: def __init__(self) -> None: self.check_init() def check_init(self): try: self.shared_data_shm = SharedMemory(name='integer', create=False) except FileNotFoundError: self.create_shared_objects() def get_value(self): return int.from_bytes(self.shared_data_shm.buf[:4], byteorder='little') def set_value(self, value): self.shared_data_shm.buf[:4] = value.to_bytes(4, byteorder='little') def create_shared_objects(self): # 创建共享内存 self.shared_data_shm = SharedMemory(name='integer', create=True, size=4) # 初始化默认值 value = 11 # 将数据写入共享内存缓冲区 self.shared_data_shm.buf[:4] = value.to_bytes(4, byteorder='little') print("共享对象已创建。") def disconnect(self): self.shared_data_shm.close() print("共享对象已断开连接。") def cleanup(self): self.shared_data_shm.unlink() print("共享对象已解除链接。")
testb.py
from testa import CommonDataHandler from time import time, sleep st = time() c = CommonDataHandler() print(f"CommonDataHandler in testb: {time()-st:.6f} seconds") for i in range(10): value = c.get_value() print(f"Value: {value}") c.set_value(i) sleep(1) c.cleanup()
testc.py
from testa import CommonDataHandler from time import time, sleep import os st = time() c = CommonDataHandler() print(f"CommonDataHandler in testc: {time()-st:.6f} seconds") print(f"Value: {c.get_value()}") c.disconnect() # sleep(1) # os.system("python3 testc.py")
运行输出
终端1运行testb.py:
py testb.py 共享对象已创建。 CommonDataHandler in testb: 0.000350 seconds Value: 11 Value: 0 Value: 1 Value: 2 Value: 3 Value: 4 Value: 5 Value: 6 Value: 7 Value: 8 共享对象已解除链接。
终端2首次运行testc.py:
CommonDataHandler in testc: 0.000304 seconds Value: 1 共享对象已断开连接。
同时弹出警告:
/usr/lib/python3.10/multiprocessing/resource_tracker.py:224: UserWarning: resource_tracker: There appear to be 1 leaked shared_memory objects to clean up at shutdown warnings.warn('resource_tracker: There appear to be %d '
终端2再次运行testc.py:
共享对象已创建。 CommonDataHandler in testc: 0.000390 seconds Value: 11 共享对象已断开连接。
同样出现上述资源泄漏警告。
取消testc.py中注释行后的运行结果:
CommonDataHandler in testc: 0.000314 seconds Value: 1 共享对象已断开连接。 CommonDataHandler in testc: 0.000280 seconds Value: 2 共享对象已断开连接。 CommonDataHandler in testc: 0.000313 seconds Value: 3 共享对象已断开连接。 CommonDataHandler in testc: 0.000330 seconds Value: 4 共享对象已断开连接。 CommonDataHandler in testc: 0.000317 seconds Value: 5 共享对象已断开连接。 CommonDataHandler in testc: 0.000325 seconds Value: 6 共享对象已断开连接。 CommonDataHandler in testc: 0.000295 seconds Value: 7 共享对象已断开连接。 CommonDataHandler in testc: 0.000302 seconds Value: 8 共享对象已断开连接。 CommonDataHandler in testc: 0.000307 seconds Value: 9 共享对象已断开连接。 共享对象已创建。 CommonDataHandler in testc: 0.000375 seconds Value: 11 共享对象已断开连接。
问题原因与解决方法
核心问题
- 共享内存被提前销毁:
testb.py运行结束时调用cleanup()执行unlink(),直接销毁了共享内存,导致后续testc.py重启后找不到原内存,只能重新创建并读取初始值11。 - 资源泄漏警告:虽然
testc.py调用了disconnect()关闭共享内存,但Python的resource_tracker可能因进程退出时的资源清理顺序问题,误报资源泄漏。
解决步骤
1. 让共享内存长期存活
修改testb.py,不在进程结束时销毁共享内存,改为手动控制销毁时机:
# 修改后的testb.py from testa import CommonDataHandler from time import time, sleep st = time() c = CommonDataHandler() print(f"CommonDataHandler in testb: {time()-st:.6f} seconds") for i in range(10): value = c.get_value() print(f"Value: {value}") c.set_value(i) sleep(1) # 仅断开连接,不销毁共享内存 c.disconnect() # 等待用户输入后再销毁 print("共享内存保持存活,按任意键销毁...") input() c.cleanup()
2. 自动释放资源避免警告
在testa.py的CommonDataHandler类中添加__del__方法,确保对象被回收时自动关闭共享内存:
# 在CommonDataHandler类中新增 def __del__(self): if hasattr(self, 'shared_data_shm'): self.shared_data_shm.close()
3. 防止重复创建共享内存
如果需要确保只有一个进程创建共享内存,可添加文件锁等同步机制,避免多进程同时触发创建逻辑。
验证效果
- 运行修改后的
testb.py,循环结束后共享内存仍保持存活,多次运行testc.py都能连接到同一内存并读取最新值。 - 按下
testb.py的输入键后,共享内存被销毁,后续testc.py会重新创建。
内容的提问来源于stack exchange,提问作者Alperen Ölçer
相关产品推荐
相关产品推荐

