使用Python Multiprocessing Pool出现‘too many open files’错误求助
解决multiprocessing.Pool spawn模式下"too many open files"错误
问题分析
你使用spawn模式创建20进程的Pool,循环100次处理约400个任务,出现OSError: too many open files,核心原因大概率是进程资源未彻底释放或任务内部存在文件句柄/资源泄漏:
spawn模式下,每个子进程都会重新初始化Python解释器、导入模块,若池长期复用,子进程积累的未释放资源(如Torch的CUDA句柄、IPC套接字)会导致句柄耗尽;- 任务函数中Torch张量未显式销毁,或循环中未正确消费任务结果,导致套接字/资源残留。
解决方案
1. 修正池的生命周期:每次迭代重新创建并销毁池
将Pool的创建移入循环内部,确保每次迭代后子进程被彻底销毁,避免长期运行的子进程积累资源:
C=100 dim_candidates = list(range(C)) best_dims = [] for i in range(C): print(f"Iteration {i+1}") # 每次迭代重新生成dargs(基于当前best_dims) dargs = [(best_dims + [dc], pos_embeddings[:, best_dims + [dc], :], neg_embeddings[:, best_dims + [dc], :]) for dc in dim_candidates] print("Number of tasks to be executed (number of candidates):", len(dargs)) # 每次迭代创建新池,with块结束自动close+join,销毁所有子进程 with multiprocessing.get_context("spawn").Pool(n_workers) as pool: results = tqdm(pool.imap(calc, dargs)) new_d, dim_scores = zip(*results) # 后续处理:移除最优维度、更新best_dims等 # ...
2. 任务函数内显式释放资源
在calc函数末尾销毁所有Torch张量,避免子进程内存/句柄泄漏:
def calc(args): dim_selected, pos_embeddings, neg_embeddings = args I = torch.eye(len(dim_selected)) max_dist = [] N, C, HW = pos_embeddings.size() for p in range(HW): mean_neg = torch.mean(neg_embeddings[:, :, p], dim=0) cov_neg = torch.cov(neg_embeddings[:, :, p].T) covI = torch.inverse(cov_neg + 0.01 * I) # 用生成器表达式代替列表推导,减少内存占用 current_max = max(mahalanobis(p_sample, mean_neg, VI=covI) for p_sample in pos_embeddings[:, :, p]) max_dist.append(current_max) # 销毁当前循环的张量 del mean_neg, cov_neg, covI # 销毁函数内的大张量 del pos_embeddings, neg_embeddings, I # 若使用GPU,清空CUDA缓存 if torch.cuda.is_available(): torch.cuda.empty_cache() return dim_selected[-1], max(max_dist)
3. 确保任务结果被完全消费
imap返回的迭代器必须被完全遍历,否则Pool会保留未完成任务的套接字。zip(*results)会强制遍历所有结果,这一步没问题,但要避免中途中断迭代。
4. 临时调大系统文件句柄上限(治标)
如果以上方法仍未解决,可临时调大系统的文件句柄限制(仅Linux/macOS):
# 临时生效,重启后失效 ulimit -n 65535
长期生效需修改/etc/security/limits.conf(Linux)或/etc/sysctl.conf。
5. 排查句柄泄漏来源
用lsof命令定位哪个进程/资源占用大量句柄:
# 查看主进程的句柄情况 lsof -p <主进程PID> | wc -l # 查看子进程的句柄情况 lsof -p <子进程PID> | grep -E "(TCP|CUDA|REG)"
若发现大量TCP套接字,说明Pool的IPC通信未正确释放;若出现大量CUDA相关句柄,说明Torch资源未销毁。
内容的提问来源于stack exchange,提问作者Mitch
相关产品推荐
相关产品推荐

