ls扫描大目录卡顿本质是内核需读取解析全部dentry和inode、排序后返回;ext4的dir_index仅加速单次查找,不优化全量枚举;大量未回收inode或NFS远程stat会进一步加剧延迟。
为什么 ls 扫描大目录会卡住几秒甚至更久
本质是内核要读取并解析整个目录的 dentry 缓存 + inode 信息,再按字母序排序后返回——不是“列个表就完事”。目录项(dentries)数量超过几万时,ls 默认的 readdir() + qsort() 流程就会明显拖慢。
- ext4 默认启用
dir_index(哈希树索引),但ls仍需遍历全部条目来排序,索引只加速单次查找,不加速全量枚举 - 如果目录下有大量已删除但未被回收的
inode(比如进程正打开着已删文件),ls会卡在stat()阶段等待超时 - 网络文件系统(如 NFS)上大目录更慢,因为每次
stat()都可能触发远程 RPC 调用
find . -maxdepth 1 -name "*" 比 ls 快吗
不一定快,但行为不同:find 默认不排序、不调用 stat()(除非用 -ls 或 -print0 以外的动作),所以对纯列举场景常更快。但它依然要遍历整个目录结构,底层仍是 readdir()。
- 加
-printf "%f\n"可避免stat(),比ls纯列名快不少 - 若目录启用了
dir_index,find的遍历顺序是磁盘物理顺序,而非字典序,结果看起来“乱” -
find . -maxdepth 1 | head -n 100无法中断遍历——find会先吐完全部再交给head,实际没提速
怎样真正跳过排序和 stat 实现毫秒级列举
绕过 shell 工具,直接用最小开销的系统调用组合。核心是:不用 getdents() 之后再 stat(),也不做任何内存排序。