9

我正在编写一个应该处理许多小文件的程序,比如数千甚至数百万。我一直在用 500k 文件测试该部分,第一步只是迭代一个目录,其中包含大约 45k 目录(包括子目录的子目录等)和 500k 小文件。遍历所有目录和文件,包括获取文件大小和计算总大小大约需要 6 秒。现在,如果我尝试在遍历时打开每个文件并立即关闭它,它看起来就像它永远不会停止。事实上,它需要的时间太长(几个小时......)。由于我在 Windows 上执行此操作,因此我尝试使用 CreateFileW、_wfopen 和 _wopen 打开文件。我没有在文件上读取或写入任何内容,尽管在最终实现中我只需要读取。但是,我在任何尝试中都没有看到明显的改进。

我想知道是否有更有效的方法来使用任何可用函数打开文件,无论是 C、C++ 还是 Windows API,或者唯一更有效的方法是直接读取 MFT 并读取磁盘块,我我想避免吗?

更新:我正在处理的应用程序正在使用版本控制进行备份快照。因此,它也有增量备份。500k 文件的测试是在一个巨大的源代码存储库上完成的,以便进行版本控制,类似于 scm。因此,所有文件都不在一个目录中。也有大约 45k 目录(如上所述)。

因此,压缩文件的建议解决方案无济于事,因为备份完成后,即会访问所有文件。因此,我不会从中受益,甚至会产生一些性能成本。

4

5 回答 5

8

对于任何操作系统来说,你想要做的事情本质上都很难有效地完成。45,000 个子目录无论如何切片都需要大量磁盘访问。

就 NTFS 而言,任何超过 1,000 字节的文件都是“大”的。如果有办法使大多数数据文件小于约 900字节,则可以通过将文件数据存储在 MFT 中来实现主要效率。那么获取数据不会比获取文件的时间戳或大小更昂贵。

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

一种策略是将文件分发到多台计算机(可能有数千台计算机)上,并在每个处理本地文件的过程中都有一个子应用程序,将任何结果提供给主应用程序。

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

于 2015-01-08T20:09:53.270 回答
3

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

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

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

您也可以尝试使用OpenFileById(),它可能对大目录中的文件执行得更好,因为它绕过了枚举目录树的需要。但是,我自己从未尝试过,并且它可能不会产生太大影响,因为如果您只是枚举它,无论如何该目录可能会被缓存。

您还可以通过从 MFT 读取它们来更快地枚举磁盘上的文件,尽管这听起来好像目前对您来说不是瓶颈。

于 2015-01-08T21:18:28.027 回答
2

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

于 2015-01-08T16:36:34.490 回答
1

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

正如我在评论中发布的那样,在单个 NTFS 目录中拥有大量条目会带来很多性能问题。因此,如果您可以控制这些文件在目录之间的分布方式,您可能希望利用这一点。

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

在尝试提高性能时,最好设定一个目标。多快才够快?

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

默认情况下,打开和关闭每个文件都会更新索引中的上次访问时间。您可以尝试一个实验,通过注册表命令行关闭该功能,看看它有多大的不同。我不确定在您的实际产品中是否可行,因为它是一个全局设置。

于 2015-01-08T19:05:56.897 回答
1

NTFS 处理大量文件时速度较慢。特别是如果它们在同一个目录中。当它们被分成单独的目录和子目录时,访问速度更快。我有许多由摄像机板(4 个摄像机)存储的文件的经验,甚至看不到文件的数量和大小(根文件夹上的属性)也太慢了。有趣的是,当磁盘是 FAT32 时,同样的速度要快得多。所有消息来源都说 NTFS 更快......也许读取单个文件更快,但目录操作更慢。

为什么需要这么多文件?我希望启用目录索引服务。

于 2015-01-08T21:51:32.297 回答