![为什么按名称删除文件速度慢得令人痛苦,但速度却异常快?](https://linux22.com/image/42686/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%8C%89%E5%90%8D%E7%A7%B0%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%E9%80%9F%E5%BA%A6%E6%85%A2%E5%BE%97%E4%BB%A4%E4%BA%BA%E7%97%9B%E8%8B%A6%EF%BC%8C%E4%BD%86%E9%80%9F%E5%BA%A6%E5%8D%B4%E5%BC%82%E5%B8%B8%E5%BF%AB%EF%BC%9F.png)
失礼之处:我下面提到的“快速”方法并不比慢速方法快 60 倍。速度快了 30 倍。我会把这个错误归咎于时间(凌晨 3 点不是我一天中清晰思考的最佳时间:)..
更新:我添加了测试时间摘要(如下)。
速度因素似乎涉及两个问题:
- 使用命令的选择(时间比较如下所示)
- 目录中存在大量文件的本质...似乎“大就是坏”。随着数量的增加,事情变得不成比例地变慢。
所有测试均使用 100 万个文件完成。
(真实时间、用户时间和系统时间位于测试脚本中)
测试脚本可以在以下位置找到:粘贴.ubuntu.com
#
# 1 million files
# ===============
#
# |time |new dir |Files added in ASCENDING order
# +---- +------- +-------------------------------------------------
# real 01m 33s Add files only (ASCENDING order) ...just for ref.
# real 02m 04s Add files, and make 'rm' source (ASCENDING order)
# Add files, and make 'rm' source (DESCENDING order)
# real 00m 01s Count of filenames
# real 00m 01s List of filenames, one per line
# ---- ------- ------
# real 01m 34s 'rm -rf dir'
# real 01m 33s 'rm filename' via rm1000filesPerCall (1000 files per 'rm' call)
# real 01m 40s 'rm filename' via ASCENDING algorithm (1000 files per 'rm' call)
# real 01m 46s 'rm filename' via DESCENDING algorithm (1000 files per 'rm' call)
# real 21m 14s 'rm -r dir'
# real 21m 27s 'find dir -name "hello*" -print0 | xargs -0 -n 1000 rm'
# real 21m 56s 'find dir -name "hello*" -delete'
# real 23m 09s 'find dir -name "hello*" -print0 | xargs -0 -P 0 rm'
# real 39m 44s 'rm filename' (one file per rm call) ASCENDING
# real 47m 26s 'rm filename' (one file per rm call) UNSORTED
#
我最近创建并删除了10万个空测试文件。按名称删除文件(即rm filename
),我艰难地发现有一个巨大的两种不同方法之间的时间差...
两种方法都使用完全相同的rm filename
命令。
更新:事实证明,这些命令并不完全相同...其中一个是一次向“rm”发送 1000 个文件名...这是一个 shell 大括号扩展问题,我认为每个文件名都被写入到 feeder 文件单独一行,但实际上每行 1000 个
文件名是通过“馈送文件”提供到while read
循环中的。
馈送文件是 的输出ls -1 -f
这些方法在所有方面都是相同的,除了一件事:
- 这慢的方法直接使用未排序的 feeder 文件
ls -1 -f
- 这快速地方法使用同一未排序文件的排序版本
我不确定排序是否是这里的问题,或者排序后的馈送文件是否恰好与创建文件的顺序匹配(我使用了简单的升序整数算法)
对于 100 万个文件,快速地 rm filename
方法是60比慢的方法...再说一次,我不知道这是一个“排序”问题,还是幕后哈希表问题...我怀疑这不是一个简单的排序问题,因为为什么会ls -1 -f
故意给我一个取消排序新添加的“排序”文件名序列的列表...
我只是想知道这里发生了什么,所以不需要我几天(是的几天)来删除接下来的 1000 万个文件:) ....我说“天”是因为我尝试了很多替代方案,并且涉及的时间与涉及的文件数量不成比例地增加..所以我只测试过1万详细
顺便说一句:通过名称的“排序列表”删除文件实际上比“排序列表”方法快rm -rf
2 倍。
并且:rm -r
比“排序列表”方法慢 30 倍
...但是这里的问题“排序”了吗?或者它与 ext4 使用的散列(或其他)存储方法更相关?
让我很困惑的是,每次调用rm filename
都与前一个无关..(好吧,至少从“bash”的角度来看是这样)
我正在使用 Ubuntu / bash / 'ext4' / SATA II 驱动器。
答案1
rm -r 预计会因为递归而变慢。必须对目录结构进行深度优先遍历。
那么你是如何创建 1000 万个文件的呢?你是否使用了一些按某种顺序循环的脚本? 1.txt,2.txt,3.txt...如果是,那么这些文件也可能以相同的顺序分配在 hdd 中的连续块中。因此按相同的顺序删除会更快。
“ls -f”将启用 -aU,它按目录顺序列出,这又是递归的。
答案2
您应该优化文件结构。所以而不是
for i in $(seq 1 1000); do touch file.$i; done
做一些更聪明的事情,比如(bash 假设):
function bucklocate()
{
hash=$(echo -n "$1"|md5sum|cut -f1);
echo -n "${hash:1:1}/${hash:7:1}/${hash:9:2}/$1";
}
hexdig="{0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}"
eval mkdir -p $hexdig/$hexdig/$hexdig$hexdig
for i in $(seq 1 1000); do touch $(bucklocate file.$i); done
现在这个例子相当慢,因为使用了 md5sum[1],使用类似下面的东西可以更快地响应,只要你不需要任何特定的文件名,重复就不用担心,也不需要某个名称的可重复哈希:)
mkdir -pv {0,1,2,3,4,5,6}/{0,1,2,3,4,5,6,7,8,9,10,12}
for a in $(seq 1 100); do i=$RANDOM; echo touch "$(($i%7))/$(($i%13))/file.$i"; done
当然,这都是草率地借用哈希表的概念