首页 > 解决方案 > 为什么 os.scandir() 变慢/如何重新组织巨大的目录?

问题描述

我有一个目录,其中包含 300 万多个文件(我应该首先避免创建)。使用 os.scandir() 简单地打印出名称,

for f in os.scandir():
    print(f)

对于前 200,000 个文件,每个项目需要 0.004 秒,但会大幅减慢到每个项目 0.3 秒。再次尝试时,它做了同样的事情——前约 200,000 人快速,然后慢下来。

在等待一个小时并再次运行后,这一次对于前 400,000 个文件来说速度很快,但随后以同样的方式变慢了。

这些文件都从 1908 年到 1963 年之间的一年开始,所以我尝试使用 bash 命令重新组织文件,例如

for i in {1908..1963}; do 
> mkdir ../test-folders/$i; 
> mv $i* ../test-folders/$i/; 
> done

但它最终被挂断,永远无法到达任何地方......

关于如何重新组织这个巨大的文件夹或更有效地列出目录中的文件的任何建议?

标签: pythonoperating-systemscandir

解决方案


钱币。那是很多文件。我不确定为什么 python 开始变慢,这很有趣。但是你遇到问题的原因有很多。一,目录可以被认为是一种特殊类型的文件,它只保存其中所有文件的文件名/数据指针(非常简化)。当操作系统在内存中缓存一些信息以加速整个系统的磁盘访问时,它可以更快地访问任何文件。

python变得更慢似乎很奇怪,也许你正在使用python中的内部存储器或其他一些机制。

但是,让我们解决问题的根源。您的 bash 脚本存在问题,因为每次使用*字符时,您都在强制 bash 脚本读取整个目录(并且可能按字母顺序对其进行排序)。获取列表一次然后对列表的各个部分进行操作可能更明智。也许是这样的:

/bin/ls -1 > /tmp/allfiles
for i in {1908..1963}; do
    echo "moving files starting with $i"
    mkdir ../test-folders/$i
    mv $(egrep "^$i" /tmp/allfiles) ../test-folders/$i/
done

这只会读取一次目录(有点),并会告诉您它的速度有多快。


推荐阅读