子进程必须独立创建MongoClient和GridFS实例,不可复用父进程对象;需流式读取避免OOM;参数须可pickle,ObjectId要转字符串;务必显式调用client.close()防止连接泄漏。

用 multiprocessing 启动子进程时,为什么总卡住或报 BrokenPipeError
GridFS 连接对象(GridFS 实例或底层 MongoClient)不能跨进程共享。子进程中直接复用父进程创建的 GridFS 对象,会触发连接状态混乱,常见表现是进程 hang 住、抛 BrokenPipeError 或 ConnectionResetError。
- 每个子进程必须自己新建
MongoClient和GridFS实例——不能传入父进程的对象 - 避免在全局作用域初始化客户端;把连接逻辑放进子进程函数内部,或用
initializer+ 全局变量(需注意线程/进程安全) - 显式调用
client.close()(尤其在频繁启停进程时),否则可能耗尽 socket 或 MongoDB 连接数
def download_one_file(file_id):
# ✅ 正确:子进程内独立建连
client = MongoClient('mongodb://localhost:27017/')
fs = GridFS(client['mydb'])
try:
grid_out = fs.get(file_id)
with open(f'file_{file_id}.bin', 'wb') as f:
f.write(grid_out.read())
finally:
client.close() # 防止连接泄漏
用 concurrent.futures.ProcessPoolExecutor 还是原生 multiprocessing.Pool
两者都能用,但 ProcessPoolExecutor 更轻量、异常传播更直观,适合“下载一批文件”这种无状态任务;multiprocessing.Pool 在需要精细控制进程生命周期(如预热连接池)时略灵活。
- 优先选
concurrent.futures.ProcessPoolExecutor:它自动处理异常捕获和结果收集,出错时不会静默吞掉错误 - 别设过大的
max_workers(比如 > CPU 核心数 × 2):GridFS 下载本质是 I/O 密集型,但 MongoDB 连接和网络带宽才是瓶颈,通常 4–8 足够 - 如果文件数量极大(如上万),别一次性
submit所有任务,改用map或分批提交,防内存堆积
下载大文件时内存暴涨甚至 OOM
默认调用 grid_out.read() 会把整个文件读进内存。一个 500MB 的文件就占掉同等内存,多进程并发时极易触发系统 OOM。
- 必须流式写入:
for chunk in grid_out或手动.read(chunk_size),推荐 chunk_size = 8192 或 65536 - 别用
fs.get(file_id).read()直接赋值给变量 - 注意:GridFS 的 chunk 默认大小是 255KB,但读取时仍建议按小块处理,避免单次分配过大内存页
def download_one_file(file_id):
client = MongoClient('mongodb://localhost:27017/')
fs = GridFS(client['mydb'])
try:
grid_out = fs.get(file_id)
with open(f'file_{file_id}.bin', 'wb') as f:
while True:
chunk = grid_out.read(8192) # ✅ 流式读
if not chunk:
break
f.write(chunk)
finally:
client.close()
怎么安全传入 file_id 和自定义参数(如目标路径、数据库名)
file_id 必须是 JSON 序列化安全的类型(ObjectId 不行),且所有参数都要能被 pickle ——这是多进程通信的基础限制。
立即学习“Python免费学习笔记(深入)”;
- 传
ObjectId前先转成字符串:str(obj_id),子进程中再用ObjectId(str_id)还原 - 数据库名、集合名、输出路径等字符串参数可直接传,但路径要注意各进程间的写冲突(别让多个进程写同一个文件)
- 不要传函数、类实例、打开的文件句柄、数据库连接等不可序列化对象
- 若需共享配置(如 MongoDB URI),建议用环境变量或配置文件,而非参数传递
MongoDB 的连接池和 GridFS 的 chunk 读取机制,在多进程下容易暴露边界问题:不是代码写错,而是对“进程隔离性”的直觉偏差。最常漏掉的是子进程里没关 client,跑一会儿就连不上了。










