Python shared_memory.SharedMemoryManager 怎样批量清理共享段
如果一个任务同时创建了多个共享内存段,真正麻烦的往往不是“怎么创建”,而是结束时记住每个对象的名字、句柄和释放顺序。Python 的 SharedMemoryManager 适合把这部分责任收拢起来:由管理器创建的 SharedMemory 和 ShareableList 会被纳入同一个生命周期,退出时调用 shutdown() 就能批量触发释放。
官方文档:https://docs.python.org/3/library/multiprocessing.shared_memory.html
批量清理的关键不是给每个共享段写一套重复的unlink(),而是让所有共享对象都从同一个SharedMemoryManager创建,并把管理器放进with或明确的try/finally边界。
先分清 close、unlink 和 shutdown
共享内存清理容易混淆,是因为“关闭当前进程的访问句柄”和“删除底层共享段”是两件事。SharedMemory.close() 只关闭当前实例持有的文件描述符或句柄;当共享段已经不再被任何进程使用时,才由 unlink() 删除底层对象。不同进程可能各自持有同一段的句柄,所以不能把一次 close() 理解成全局删除。
SharedMemoryManager.shutdown() 的职责更高一层:它会对通过该管理器创建的共享内存对象触发 unlink(),然后停止管理器进程。也就是说,文章标题里的“批量”来自管理器保存的对象集合,而不是调用方自己维护一个共享段列表。

让所有共享对象由同一个管理器创建
需要批量清理时,创建入口要保持一致。下面同时创建一个固定长度的 ShareableList 和一个原始 SharedMemory 段;它们都挂在同一个管理器下面,后续只需要处理管理器的生命周期。
from multiprocessing.managers import SharedMemoryManager
def create_shared_objects():
# start() 会启动负责管理共享对象生命周期的服务进程。
manager = SharedMemoryManager()
manager.start()
try:
# 通过管理器创建的对象会进入同一个待清理集合。
values = manager.ShareableList([0, 0, 0, 0])
raw_block = manager.SharedMemory(size=128)
return manager, values, raw_block
except Exception:
# 创建中途失败时,确保已经创建的对象不会遗留。
manager.shutdown()
raise
这里的关键不在变量名,而在创建路径:如果改成直接调用 SharedMemory(create=True, ...),那个对象就不再自动属于这个管理器,调用方必须自行保存句柄并规划 close() 与 unlink()。
用 with 语句覆盖正常退出和异常退出
更适合业务代码的写法是使用上下文管理器。进入 with 时启动管理器,离开代码块时调用 shutdown();无论是正常走到末尾,还是代码块中抛出了异常,清理边界都集中在同一个位置。
from multiprocessing import Process
from multiprocessing.managers import SharedMemoryManager
def fill_range(shared_values, start, end):
# 子进程只写自己的区间,避免多个进程同时改同一个槽位。
for index in range(start, end):
shared_values[index] = index * index
def run_job():
# 离开 with 时由管理器统一释放内部创建的共享对象。
with SharedMemoryManager() as manager:
shared_values = manager.ShareableList([0] * 8)
workers = [
Process(target=fill_range, args=(shared_values, 0, 4)),
Process(target=fill_range, args=(shared_values, 4, 8)),
]
for worker in workers:
# 先启动所有工作进程,再等待它们访问共享列表。
worker.start()
for worker in workers:
worker.join()
# 子进程都结束后再读取结果,避免清理边界与访问边界重叠。
if any(worker.exitcode != 0 for worker in workers):
raise RuntimeError("worker exited with an error")
return list(shared_values)
if __name__ == "__main__":
print(run_job())
这个示例的返回值只是业务结果,清理动作由 with 的退出逻辑负责。不要在 with 内部提前对管理器创建的共享段调用 unlink(),否则后续仍持有的引用可能访问到已被删除的底层对象。

多个进程时,先收拢访问再关闭管理器
管理器可以批量释放资源,但它不会替调用方等待业务进程完成。实际工程里应先让工作进程结束,再离开 with 或显式调用 shutdown()。否则管理器已经删除共享段,而工作进程还在读写,就会把资源释放问题变成并发时序问题。
如果工作进程可能卡住,可以把等待和兜底终止写在清理逻辑里,但终止进程仍然是业务层的职责。管理器负责共享段生命周期,进程编排负责保证没有活跃访问者,两个职责不要混在一个“清理函数”里。
def wait_workers(workers, timeout):
# 先给正常退出留出时间,避免无条件终止正在写共享数据的进程。
for worker in workers:
worker.join(timeout)
for worker in workers:
if worker.is_alive():
# 只有超时仍未退出时才做进程级兜底。
worker.terminate()
worker.join()
独立 SharedMemory 连接不能混用管理器语义
有些场景是一个进程创建共享段,另一个独立启动的进程根据名称附加。此时附加进程拿到的只是一个访问句柄,并不自然拥有创建者的管理器上下文。附加方通常在不用时调用 close(),由约定的拥有者决定何时调用一次 unlink()。
Python 文档还提醒,非共同祖先进程各自使用资源跟踪器时,track=True 可能让第一个退出的进程触发删除;如果已经有其他进程负责记账,独立进程需要结合实际拓扑考虑 track=False。Windows 下该参数会被忽略,底层共享内存会在所有句柄关闭后由系统处理。
因此可以按下面的职责表做选择:
| 场景 | 创建方式 | 结束时的主要动作 |
|---|---|---|
| 同一任务内批量创建 | SharedMemoryManager | 等待工作进程后退出 with 或调用 shutdown() |
| 独立进程附加 | SharedMemory(name=...) | 附加方 close(),拥有者按协议调用一次 unlink() |
| 创建中途异常 | 管理器已启动但对象未全部创建 | 在 except 中调用 manager.shutdown() 后继续抛出异常 |
一份可复用的清理判断
把问题压缩成三个判断就够了:共享对象是不是由同一个管理器创建的;还有没有进程持有活跃访问;当前代码是否处在 with 或 finally 的清理边界。如果三个答案分别是“是、没有、是”,优先使用管理器的统一退出;如果共享段来自外部名称附加,则回到拥有者协议,不要把 shutdown() 当成全局回收按钮。
这套写法解决的是资源归属与退出路径,不会自动解决共享数据的并发写冲突。共享列表的槽位分配、锁、进程异常传播仍需要在业务层设计。
常见问题
SharedMemoryManager.shutdown() 会关闭所有进程的句柄吗?
它负责释放由该管理器管理的共享对象并停止管理器进程;其他进程仍应在自己的访问结束后关闭本地句柄。
只调用 close() 能删除共享内存段吗?
不能把两者等同。close() 关闭当前实例的访问,底层对象是否删除还取决于 unlink() 或平台的生命周期规则。
为什么推荐 with SharedMemoryManager()?
因为它把正常退出和异常退出都纳入同一个上下文边界,减少漏写 shutdown() 和遗留共享段的机会。
Python subprocess.Popen start_new_session 怎样清理进程组
- 上一篇
- Python subprocess.Popen start_new_session 怎样清理进程组
- 下一篇
- systemd ListenStream 与 ListenDatagram 怎么选
-
- 文章 · python教程 | 21分钟前 | Python教程 · 进程管理 · Python subprocess.Popen TimeoutExpired 进程组 start_new_session killpg
- Python subprocess.Popen start_new_session 怎样清理进程组
- 340浏览 收藏
-
- 文章 · python教程 | 23分钟前 |
- Python contextlib.chdir 为什么不适合并发任务共享
- 241浏览 收藏
-
- 文章 · python教程 | 23分钟前 | Python handler 日志过滤 logging.Filter
- Python logging.Filter 返回 False 时怎样阻止单条记录
- 447浏览 收藏
-
- 文章 · python教程 | 29分钟前 |
- Python zipfile.Path 怎样读取压缩包内的嵌套资源
- 157浏览 收藏
-
- 文章 · python教程 | 34分钟前 | 协程 · 任务调度 · Python教程 · asyncio · 兼容性 · Python asyncio 异步调度 create_task eager_start
- Python asyncio.create_task eager_start 如何影响调度
- 155浏览 收藏
-
- 文章 · python教程 | 39分钟前 | Python CancelledError TaskGroup asyncio.timeout 嵌套超时
- Python asyncio.timeout 怎样把嵌套任务限制在总时限内
- 215浏览 收藏
-
- 文章 · python教程 | 12小时前 | 并发编程 · Python教程 · Python multiprocessing Pool initializer spawn initargs 多进程配置
- Python multiprocessing spawn 传递初始化配置的方案
- 295浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 1019次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 1021次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1155次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1122次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 963次使用
-
- 物流异常件转派时如何保留原单号与处理时限
- 2026-09-20 276浏览
-
- Golang异常处理之defer,panic,recover的使用详解
- 2023-01-07 339浏览
-
- 小学生也能看懂的Golang异常处理recover panic
- 2022-12-30 485浏览
-
- 详解Go语言的错误处理和资源管理
- 2022-12-31 451浏览
-
- go格式“占位符”输入输出 类似python的input
- 2023-01-19 346浏览

