在 Ubuntu(以及一般 Linux)上,使用 opendir() + readdir() 遍历目录时,性能往往看起来比较差,通常不是 opendir 本身慢,而是整体目录遍历的代价被低估了。下面按常见原因系统说明。
opendir 本身并不慢,慢在“后续操作”opendir() 只是打开目录文件(本质是 open() + fdopendir()),开销很小。
真正耗时的是:
readdir() 逐条读取目录项readdir() 都可能触发 内核→用户态拷贝stat(),性能会急剧下降经验值:
仅opendir/readdir:几万条/秒
readdir + stat:可能降到几千条/秒
readdir 是“逐条系统调用”readdir() 是流式接口:
对比:
getdents64(底层系统调用)一次可返回很多项opendir/readdir 是在其上做了封装,更方便但更慢如果你用 strace,会看到大量:
getdents64(...)
stat() 是性能杀手(最常见)很多程序写成:
while ((ent = readdir(dir))) {
stat(ent->d_name, &st); // ❌ 很慢
}
问题:
stat 需要访问 inode✅ 改进方式:
readdir + d_type(如果文件系统支持)openat() + fstatat(AT_NO_AUTOMOUNT)| 文件系统 | opendir/readdir 性能 |
|---|---|
| ext4 | 快 |
| xfs | 快 |
| btrfs | 中等(元数据开销大) |
| NFS | 很慢 |
| overlayfs | 慢(多层查找) |
| tmpfs | 极快 |
在 Docker / Kubernetes 中,overlayfs 会明显拖慢目录遍历。
opendir 性能随:
例如:
stat这会非常慢,甚至看起来“卡死”。
✅ 建议:
第一次遍历:
time ls dir/
第二次:
time ls dir/
第二次通常快 5–10 倍,因为:
opendir 慢往往是 cold cache 造成的。
Ubuntu 默认启用:
每次 open / readdir / stat 都可能:
在高频目录遍历时影响明显。
目录不是“可并行读取”的资源:
✅ 正确做法:
ls 有时更快?ls 可能更快是因为:
getdents64 批量读取stat而手写 C 程序如果:
readdirstat反而更慢。
✅ 避免逐文件 stat
✅ 使用 d_type
✅ 减少系统调用次数
✅ 利用缓存(热路径)
✅ 避免超大单目录
✅ 避免在 NFS / overlay 上频繁遍历
如果你愿意,可以:
我可以帮你精确分析瓶颈点并给出改写方案。