OSError: [Errno 24] Too many open files 的含义是进程打开的文件句柄(文件描述符 fd)超过操作系统的上限;在你同时 zip 两个 DataLoader 的场景里,最常见诱因是 DataLoader 的多进程 worker 持续打开图片文件、句柄没有及时回收,叠加 zip 同步迭代、循环多次加载,句柄不断累积,最终触达系统限制。zip 本身不是 bug,只是让两个 DataLoader 的文件打开行为同时发生,加速了句柄耗尽。
一、报错原因拆解
| 项目 | 说明 |
|---|---|
| 报错编号 | Errno 24,文件描述符超限 |
| 触发场景 | for a, b in zip(dl1, dl2): 双 DataLoader 并行迭代 |
| 核心来源 | DataLoader 的 worker 子进程打开图片、标注文件,句柄释放不及时 |
| 加重因素 | num_workers 开太大、循环 epoch 很多、Dataset 里每次 open 不 close、PIL/OpenCV 隐式持有句柄 |
| 误区 | 不是 zip 函数本身有内存泄漏,是两个 DataLoader 同时产生大量打开文件 |
二、快速排查命令(Linux/macOS)
查看当前进程句柄上限
ulimit -n
实时监控进程打开文件数,PID替换成你的python进程id
lsof -p | wc -l
- 常见默认值:1024;如果你的 worker 多、同时开两个 loader,很容易打满。
- 观察:每跑一个 batch,lsof 数量持续上涨,就是句柄泄漏。
三、分层解决方案(按推荐顺序)
- 优先:Dataset 里打开图片后主动 close,不要依赖 GC 自动回收
PIL Image.open() 会持有文件句柄。推荐写法:
def __getitem__(self, idx):
path = self.paths[idx]
with Image.open(path) as img:
img = img.convert("RGB").resize((224,224))
tensor = transforms.ToTensor()(img)
return tensor
with 上下文退出时立刻关闭文件,是最根本解法。
- 降低 num_workers,不要开太高
两个 DataLoader,每个 worker 都会独立打开文件。
比如原来 num_workers=8,改成 2~4;双 loader 场景句柄是叠加的,不要把 worker 拉满。
注意:Windows 下多进程句柄机制不一样,更容易出现这个问题。
- 避免无限迭代、重复实例化 DataLoader
不要在 epoch 循环内部反复 DataLoader(...),每次新建都会新建一批 worker、打开一批文件;DataLoader 放在循环外面。
正确:只初始化一次
dl1 = DataLoader(ds1, num_workers=2)
dl2 = DataLoader(ds2, num_workers=2)
for epoch in range(100):
for x,y in zip(dl1, dl2):
pass
- 调高系统文件句柄上限(临时兜底方案,不推荐作为首选)
临时生效(当前终端)
ulimit -n 4096
永久修改需要改 /etc/security/limits.conf,服务器环境才适合操作,本地笔记本不建议。
- 备选:单进程加载 num_workers=0
num_workers=0 所有加载在主进程,句柄更容易回收,代价是速度变慢,适合调试定位泄漏。
四、zip 两个 DataLoader 的额外坑点
- zip 会以短的那个 loader 长度作为迭代终点;如果两个数据集长度不一样,短的跑完循环直接终止,这个和句柄报错无关,但经常一起踩坑。
- DataLoader worker 是独立子进程,子进程的文件句柄不会随主进程迭代自动释放,必须靠 Dataset 内部 close。
- 不要用 itertools.cycle 包裹 DataLoader 做无限循环,会持续累积句柄。
五、排查步骤清单
- lsof 监控进程句柄,确认是否持续上涨。
- 给所有 Image.open/cv2.imread 加上上下文管理,确保文件关闭。
- 减少 num_workers,双 loader 要算叠加量。
- 测试 num_workers=0,看报错是否消失:消失 = 问题来自 worker 子进程文件句柄泄漏。
- 检查是否循环内反复创建 DataLoader。
【相关 FAQ】
问题 1:OSError: [Errno 24] Too many open files,我用 zip 把两个 DataLoader 放一起迭代,是不是 zip 导致泄漏?
回答 1:zip 本身不会造成文件句柄泄漏;zip 只是让两个 DataLoader 同时在迭代,两个 DataLoader 的 worker 同时打开大量图片文件,句柄叠加累积,加速触达系统上限,根源是 Dataset 读取时文件没有及时关闭。
问题 2:同样的代码,只用单个 DataLoader 没事,zip 两个 DataLoader 就报 Too many open files,为什么?
回答 2:单个 DataLoader 打开的文件句柄总量在 ulimit 限制以内;zip 双 loader 时,两套 worker 进程同时打开文件,文件描述符数量叠加,短时间就突破系统上限,触发 Errno24。
问题 3:用 with Image.open () 之后还报 Too many open files,还有什么排查方向?
回答 3:检查是否还有其他文件读取:标注 json、npy、视频帧;另外确认是否反复新建 DataLoader、或者使用 cycle 无限循环 loader;也可以降低 num_workers,或者监控 lsof 定位是哪一类文件持续打开。
【参考资料】
PyTorch DataLoader multiprocessing file descriptor behavior
Linux ulimit file descriptor limit
PIL Image.open file handle leak issue
【免责声明】
ulimit 修改受操作系统、服务器权限限制,共享服务器不要随意调高全局句柄上限;Windows、WSL、macOS 的文件描述符机制和 Linux 有差异,部分方案效果不同。本文方案基于 PyTorch DataLoader 场景,TensorFlow DataLoader 机制不同。
本文来自作者[元簇同调使]投稿,不代表乌兰科技网立场,如若转载,请注明出处:https://www.wlcbnews.com/rgzn/202611/543.html
评论列表(4条)
我是乌兰科技网的签约作者“元簇同调使”!
希望本篇文章《OSError Too many open files 搭配 zip 两个 DataLoader 场景,文件描述符超限排查与解决方案》能对你有所帮助!
本站[乌兰科技网]内容主要涵盖:互联网行业的追踪与探索
本文概览:OSError: [Errno 24] Too many open files 的含义是进程打开的文件句柄(文件描述符 fd)超过操作系统的上限;在你同时 zip 两个 DataLoader 的场景里,最常见诱因是 DataLoader 的多进程 worker 持续打开图片文件、句柄没有及时回收,叠加 zip 同步迭代、循环多次加载,句柄不断累积,最终触达系统限制。zip 本身不是 bug,只是让两个 DataLoader 的文件打开行为同时发生,加速了句柄耗尽。