内存映射文件在大型顺序读取时更快?为什么?

5

我使用下面的代码来衡量内存映射文件进行大规模顺序读取与仅调用ReadFile之间性能差异:

HANDLE hFile = CreateFile(_T("D:\\LARGE_ENOUGH_FILE"),
    FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
    FILE_FLAG_NO_BUFFERING, NULL);
__try
{
    const size_t TO_READ = 32 * 1024 * 1024;
    char sum = 0;
#if TEST_READ_FILE
    DWORD start = GetTickCount();
    char* p = (char*)malloc(TO_READ);
    DWORD nw;
    ReadFile(hFile, p, TO_READ, &nw, NULL);
#else
    HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY,
        0, 0, NULL);
    const char* const p = (const char*)MapViewOfFile(hMapping,
        FILE_MAP_READ, 0, 0, 0);
    DWORD start = GetTickCount();
#endif
    for (size_t i = 0; i < TO_READ; i++)
    {
        sum += p[i]; // Do something kind of trivial...
    }
    DWORD end = GetTickCount();
    _tprintf(_T("Elapsed: %u"), end - start);
}
__finally { CloseHandle(hFile); }

我刚刚更改了TEST_READ_FILE的值来更改测试。

令我惊讶的是,ReadFile的速度慢了约20%!为什么?


你确定你不只是在观察磁盘缓存在工作吗? - Thilo
重新启动。尝试以相反的顺序进行测试。并且多次尝试。 - Thilo
@Mehrdad:计时公平吗?您在ReadFile情况下计时malloc(),但在内存映射情况下没有计时。我知道调用CreateFileMapping()和MapViewOfFile()可能很便宜,但是您的做法看起来有点尴尬。或者说这样测量时间有什么意义吗? - the swine
@theswine:这是一个非常好的观点,不幸的是,这个问题已经两年了,我对它记忆不深(我也没有同样的电脑来测试它)。我认为你可能是对的——malloc会极大地扭曲结果,因为强制每个页面都被提交以减慢速度。无论这是否公平,我都不确定……我可以反驳任何一种观点。(例如,由于文件映射不需要malloc,你可以认为这是你必须考虑的额外负担。) - user541686
@Mehrdad:我看懂了。没事了。我的意思是把开始时间移到#ifdef上面(这样只有一个)。对我来说这很公平:)。但别担心,我可以在无聊的时候在我的电脑上尝试一下。 - the swine
显示剩余14条评论
1个回答

7

FILE_FLAG_NO_BUFFERING 会破坏 ReadFile。内存映射文件可以自由地使用任何预读算法,而你禁止了 ReadFile 执行相同的操作。你只是关闭了 ReadFile 版本中的缓存设置。内存映射文件无法在没有文件缓存的情况下工作。


@Ben:等一下,为什么内存映射文件不遵守标志呢? - user541686
@Mehrdad:这怎么可能呢?MapViewOfFile使用内存管理单元将文件缓存中的页面映射到进程内存空间。 - Ben Voigt
@Ben:我对它的工作原理一无所知,但我想象它在每次访问页面时会引发页面错误,这样内核就可以接管并填充页面数据,因此实际上不需要任何缓存。 - user541686
对于大量的顺序读取,您还应该使用FILE_FLAG_SEQUENTIAL_SCAN - Ben Voigt
1
@Mehrdad:它只在第一次访问页面时执行该操作。重复读取每个页面4000次是疯狂的。而且是缓存管理器填充该页面的数据并决定何时释放它…这就是内存映射文件在进程之间保持一致的方式,因为缓存管理器将同一物理页面映射到多个进程中。你的进程不拥有内存。 - Ben Voigt
@Mehrdad:有趣的问题。无论如何,在你的情况下,FILE_FLAG_NO_BUFFERING是否恢复了20%,使得ReadFile()与内存映射一样快?在你的特定情况下最终结果是什么? - the swine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接