由于页面缓存, os.walk() 在第一个 运行 之后快得多吗?

Is os.walk() much faster after the first run due to page caching?

我使用 os.walk 迭代,比如说,1000 个文件(只是迭代,没有对这些文件进行任何处理)。 第一个 运行 很慢,但随后的 运行 s(在同一路径上)大约快 20 倍。

据我所知,os.walkos.listdir(被 os.walk 使用)没有做任何缓存,FindFirstFile/FindNextFileos.listdir 在我的 Windows 平台上使用)。

这是由于页面缓存还是其他原因造成的?

仅供参考,我正在尝试编写一个备份应用程序并且需要处理大量文件。如果确实是页面缓存的问题,那我就需要自己写一个缓存机制了。

您的 OS 在这里进行缓存;目录查找需要缓慢的磁盘访问,因此此类访问被大量缓存。

例如,ntfs.sys 驱动程序 uses the Data Map service 用于缓存目录列表等文件系统元数据。

我知道您已经找到了问题的答案,但这让我很好奇这些缓存在 Linux 中是如何工作的,所以我进行了一些基准测试。

我创建了一个包含1000个子目录的目录,在每个子目录中我创建了1000个文件。总共1000个文件夹和100万个文件。

seq 1000 | parallel "mkdir {} && seq 1000 | parallel touch {}/\{\}"

这应该会给 os.walk 一些有用的东西。接下来,我创建了一个测试脚本,它只计算目录中的文件数,递归使用 os.walk:

def count_dir(path):
    count = 0
    for _, _, files in os.walk(path):
        count += len(files)
    return count

我 运行 这几次,最终平均执行时间为 2.27 秒。

接下来,我 运行 再次测试了几次,但在每次执行之间刷新了页面缓存,然后再次刷新了 dentry/inode 缓存,最后是同样的事情,但刷新了所有以上缓存。

To free pagecache:
        echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes:
        echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:
        echo 3 > /proc/sys/vm/drop_caches

结果:

            no flush  page cache  dentries/inodes  all
mean        2.27      2.56        4.24             4.80
stdev       0.052     0.055       0.127            0.108
%RSD        2.27%     2.15%       2.99%            2.26%
median      2.26      2.54        4.21             4.78
iterations  27        27          31               10

基准测试是 运行 在新 SSD 驱动器上的 ext4 文件系统上。 Linux 版本是 3.17.7.

毫不奇怪,页面缓存和 dentries/inodes 缓存对这个基准测试的结果影响很大。然而,我有点惊讶,仅刷新页面缓存会产生如此大的差异,因为应该可以一次读取这些文件的大部分文件系统元数据,但我可能遗漏了一些东西。

我会说页面缓存并没有太大的不同,因为包含文件系统元数据的页面的缓存未命中率相对较低。但我的直觉似乎是错误的。有什么想法吗?