【问题标题】:FILE_FLAG_IO_BUFFERING slows down synchronous read operationFILE_FLAG_IO_BUFFERING 减慢同步读取操作
【发布时间】:2013-07-20 19:35:21
【问题描述】:

使用标志 FILE_FLAG_IO_BUFFERING 读取一组没有缓冲的文件(跳过文件缓存)应该比正常读取(不使用此标志)更快。更快的原因是“无缓冲”机制将跳过系统文件缓存并直接读入应用程序的缓冲区。
应用程序在冷环境下运行(磁盘碎片整理后,机器重启),因此系统文件缓存不会与运行前的相关文件一起缓存。
这是来自有关这些 API 和标志的 msdn 文档。

但是,我遇到了完全不同的性能行为。在使用 FILE_FLAG_IO_BUFFERING 标志创建文件句柄之后,我一个接一个地同步读取一组文件。读取这组文件所需的时间是 29 秒。如果我在不使用此标志的情况下正常读取(再次在文件缓存不保存相关文件时在应用程序的冷运行中),则所需时间约为 24 秒。

详情
文件总数:1939
总文件大小(总和):57 MB
使用 FLAG_IO_NO_BUFFERING:29 秒(读取时间)
没有 FLAG_IO_NO_BUFFERING:24 秒(读取时间)

下面是实现读取的代码:

DWORD ReadFiles(std::vector<std::string> &filePathNameVectorRef)
{
    long totalBytesRead = 0;    
    for(all file in filePathNameVectorRef)
        totalBytesRead += Read_Synchronous(file);           
    return totalBytesRead;
}

DWORD Read_Synchronous(const char * filePathName)
{
    DWORD accessMode = GENERIC_READ;
    DWORD shareMode = 0;
    DWORD createDisposition = OPEN_EXISTING;
    DWORD flags = FILE_FLAG_NO_BUFFERING;
    HANDLE handle = INVALID_HANDLE_VALUE;
    DWORD fileSize;
    DWORD bytesRead = 0;
    DWORD bytesToRead = 0;
    LARGE_INTEGER li;
    char * buffer;  
    BOOL success = false;


    handle = CreateFile(filePathName, accessMode, shareMode, NULL, createDisposition, flags, NULL);
    if(handle == INVALID_HANDLE_VALUE)
          return 0;

    GetFileSizeEx(handle, &li);
    fileSize = (DWORD)li.QuadPart;

    bytesToRead = (fileSize/g_bytesPerPhysicalSector)*g_bytesPerPhysicalSector;
    buffer = static_cast<char *>(VirtualAlloc(0, bytesToRead, MEM_COMMIT, PAGE_READWRITE));

    if(buffer == NULL)
         goto RETURN;

    success = ReadFile(handle, buffer, bytesToRead, &bytesRead, NULL);

    if(!success){
        fprintf(stdout, "\n Error occured: %d", GetLastError());
        return 0;
    }

    free(buffer);

RETURN:
    CloseHandle(handle);
    return bytesRead;
}

请分享您认为此代码运行速度比未使用 FILE_FLAG_NO_BUFFERING 时慢的原因。谢谢。

【问题讨论】:

  • 如果您总是按顺序阅读,您可以尝试添加FILE_FLAG_SEQUENTIAL_SCAN 标志,看看是否有帮助。
  • 当您跳过缓存时,您也将跳过它具有的美妙选项,能够将整个曲目读取到缓存中。这非常便宜,因为无论如何驱动头已经位于正确的位置,这是免费数据。

标签: c++ windows winapi file-io


【解决方案1】:

我希望您测量的是打开和关闭文件的时间。文件比较多。您应该能够在一秒钟左右从磁盘读取 57MB。所以开销似乎是文件打开而不是读取。您应该使用更少但更大的文件重试。比如说,创建 20 个 100MB 的文件并阅读它们。至少在您的系统上,使用FILE_FLAG_NO_BUFFERING 打开文件似乎比没有打开文件要慢。

无论如何,不​​要指望FILE_FLAG_NO_BUFFERING 会加快速度。与从磁盘中提取数据相比,从文件句柄的缓冲区复制到缓冲区所花费的时间微不足道。

【讨论】:

    猜你喜欢
    • 2021-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    • 2016-03-31
    相关资源
    最近更新 更多