13

我需要按顺序读取(扫描)文件并处理其内容。文件大小可以从非常小(一些 KB)到非常大(一些 GB)。

我在 Windows 7 64 位上使用 VC10/VS2010 尝试了两种技术:

  1. Win32 内存映射文件(即 CreateFile、CreateFileMapping、MapViewOfFile 等)
  2. fopen 和 fread 从 CRT。

我认为内存映射文件技术可能比 CRT 函数更快,但一些测试表明两种情况下的速度几乎相同。

以下 C++ 语句用于 MMF:

HANDLE hFile = CreateFile(
    filename,
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_SEQUENTIAL_SCAN,
    NULL
    );

HANDLE hFileMapping = CreateFileMapping(
    hFile,
    NULL,
    PAGE_READONLY,
    0,
    0,
    NULL
    );

文件被顺序读取,逐块读取;每个块SYSTEM_INFO.dwAllocationGranularity的大小。

考虑到 MMF 和 CRT 的速度几乎相同,我会使用 CRT 函数,因为它们更简单且多平台。但我很好奇:我是否正确使用了 MMF 技术?在这种顺序扫描文件的情况下,MMF 性能与 CRT 相同是否正常?

谢谢。

4

4 回答 4

14

如果您按顺序访问文件,我相信您不会看到太大的区别。因为文件 I/O 被大量缓存,可能也使用 + 预读。

如果在文件数据处理过程中有很多“跳跃”,情况就会有所不同。然后,每次设置新文件指针并读取新文件部分可能会杀死 CRT,而 MMF 将为您提供最大可能的性能

于 2010-10-20T16:26:46.053 回答
4

由于您是按顺序扫描文件,因此我不认为这两种方法的磁盘使用模式会有很大不同。

对于大文件,MMF 可能会降低数据局部性,甚至会导致将文件的全部或部分副本放置在页面文件中,而使用小缓冲区通过 CRT 进行的处理都将在 RAM 中进行。在这种情况下,MMF 可能会更慢。您可以通过一次仅映射部分基础文件来缓解这种情况,但随后事情会变得更加复杂,而没有任何可能胜过直接顺序 I/O。

MMF 实际上是 Windows 实现进程间共享内存的方式,而不是加速通用文件 I/O 的方式。内核中的文件管理器缓存是您真正需要在这里利用的。

于 2010-10-20T16:27:35.527 回答
2

我认为内存映射文件技术可能比 CRT 函数更快,但一些测试表明两种情况下的速度几乎相同。

您可能正在为您的测试访问文件系统缓存。除非您显式创建文件句柄以绕过文件系统缓存(FILE_FLAG_NO_BUFFERING调用时CreateFile),否则文件系统缓存将启动并将最近访问的文件保存在内存中。

在打开缓冲的情况下读取文件系统缓存中的文件之间存在小的速度差异,因为操作系统必须执行额外的复制以及系统调用开销。但出于您的目的,您可能应该坚持使用 CRT 文件功能。

Gustavo Duarte 有一篇关于内存映射文件的精彩文章(从通用操作系统的角度来看)。

于 2010-10-20T16:54:42.477 回答
1

这两种方法最终都会归结为磁盘 i/o,这将是您的瓶颈。我会使用我的高级功能更喜欢的一种方法 - 如果我需要流式传输,我会使用文件,如果我需要顺序访问和固定大小的文件,我会考虑内存映射文件。

或者,如果您有一个仅适用于内存的算法,那么内存映射文件可能更容易解决。

于 2010-10-20T16:35:50.460 回答