C++ 在NTFS上打开许多小文件太慢了

C++ 在NTFS上打开许多小文件太慢了,c++,windows,performance,ntfs,directory-traversal,C++,Windows,Performance,Ntfs,Directory Traversal,我正在写一个程序,可以处理很多小文件,比如说几千甚至几百万个。 我已经在500k文件上测试了这一部分,第一步只是迭代一个目录,其中包含大约45k个目录(包括subdirs的subdirs等)和500k个小文件。遍历所有目录和文件(包括获取文件大小和计算总大小)大约需要6秒钟。现在,如果我尝试在遍历时打开每个文件并立即关闭它,它看起来好像从未停止过。事实上,它花费的时间太长(几个小时…)。由于我在Windows上执行此操作,因此我尝试使用CreateFileW、\u wopen和\u wopen打

我正在写一个程序,可以处理很多小文件,比如说几千甚至几百万个。 我已经在500k文件上测试了这一部分,第一步只是迭代一个目录,其中包含大约45k个目录(包括subdirs的subdirs等)和500k个小文件。遍历所有目录和文件(包括获取文件大小和计算总大小)大约需要6秒钟。现在,如果我尝试在遍历时打开每个文件并立即关闭它,它看起来好像从未停止过。事实上,它花费的时间太长(几个小时…)。由于我在Windows上执行此操作,因此我尝试使用CreateFileW、\u wopen和\u wopen打开文件。我没有在文件上读写任何东西,尽管在最终的实现中我需要只读。然而,我没有看到任何一次尝试都有明显的改善

我想知道是否有一种更有效的方法来打开文件,无论是C、C++还是Windows API,或者唯一更有效的方法是直接读取磁盘的MFT和读块,我试图避免它。 更新:我正在使用的应用程序正在使用版本控制进行备份快照。因此,它还有增量备份。使用500k文件的测试是在一个巨大的源代码存储库上进行的,以便进行版本控制,类似于scm。因此,并非所有文件都在一个目录中。还有大约45k个目录(如上所述)


因此,建议的压缩文件的解决方案没有帮助,因为备份完成后,所有文件都会被访问。因此,我看不出这有什么好处,甚至会带来一些性能成本。

有一种方法可以尝试:用低压缩比压缩这些文件,然后使用一些压缩库来读取它们,这通常比逐个读取单个文件快得多。
当然,这应该作为预处理步骤提前完成。

您可以尝试执行一次过程,将文件枚举到数据结构,然后在第二次过程中打开和关闭它们,以查看交错操作是否会导致争用

正如我在评论中所发布的,在单个NTFS目录中有大量条目存在许多性能问题。因此,如果您可以控制这些文件在目录中的分布方式,您可能希望利用这一点

还要检查系统上的反恶意软件。有些会在每次尝试访问整个文件时扫描整个文件,从而降低每个文件的访问速度。使用Sysinternals Procmon可以帮助您发现此类问题

当试图提高绩效时,设定目标是个好主意。多快才算足够快

编辑:除非您使用的是Windows XP或更早版本,否则原始答案的这一部分不适用:


默认情况下,打开和关闭每个文件将更新索引中的上次访问时间。你可以尝试一个关闭该功能的实验,或者看看它有多大的不同。我不确定在您的实际产品中这样做是否可行,因为这是一个全球性的设置。

对于任何操作系统来说,您试图做的事情本质上都是很难有效完成的。45000个子目录需要大量磁盘访问,无论它是如何切片的

就NTFS而言,任何超过1000字节的文件都是“大”文件。如果有一种方法可以使大多数数据文件小于约900字节,那么您可以通过将文件数据存储在MFT中来实现更高的效率。然后,获取数据的成本不会比获取文件的时间戳或大小更高

我怀疑是否有任何方法可以优化程序的参数、进程选项,甚至操作系统的调整参数,以使应用程序正常工作。除非你能以完全不同的方式重新构建,否则你将面临长达数小时的操作

一种策略是将文件分发到多台计算机上,可能有数千台,并且在每个进程上都有一个子应用程序—本地文件,将任何结果提供给主应用程序


另一个策略是将所有文件重新构建为几个更大的文件,如@felicepollano建议的大.zip文件,有效地虚拟化您的文件集。随机访问4000 GB的文件本质上比访问40亿个1 MB的文件更高效、更有效地利用资源。同时,将所有数据移动到合适的数据库管理器(MySQL、SQL Server等)中也可以实现这一点,并可能提供其他好处,如轻松搜索和轻松存档策略。

对于具有该数量文件的NTFS卷来说,每个文件5到20ms的开销并不反常。(在传统的轴驱动器上,无论如何,您都不能期望比这更好的结果,因为它的顺序与磁头寻道时间相同。从这一点上,我假设我们正在处理企业级硬件、SSD和/或RAID。)

根据我的经验,通过并行化请求(即使用多个线程和/或进程),可以显著提高吞吐量。大部分开销似乎是每个线程的,系统一次可以打开十个文件,几乎和它自己打开一个文件的速度一样快。我不知道这是为什么。您可能需要进行实验以找到最佳的并行化级别

系统管理员还可以通过将内容复制到新卷(最好是以与访问顺序大致相同的顺序)来显著提高性能。我最近不得不这样做,它将备份时间(对于一个包含大约1400万个文件的卷)从85小时减少到了18小时

您还可以尝试对大目录中的文件执行更好的操作,因为它绕过了枚举目录树的需要。但是,我自己从来没有尝试过,而且可能没有太大影响,因为如果