异步/重叠文件读取没有内核开销?

问题描述 投票:0回答:1

我对 win32 ReadFile() 重叠 I/O 并不是很满意,因为它确实不可靠,并且在 DEBUG 配置中的内核开销为 8-10 毫秒,在 RELEASE 配置(Visual Studio)中为 400mb,内核开销为 25-30 毫秒,内核开销与读取的字节大小成正比...我已经报告了这一点: https://developercommunity.visualstudio.com/t/Overlapping-ReadFile-takes-significantly/10475365

重现步骤:

  1. 在 Visual Studio 中创建新项目,然后选择控制台应用程序
  2. 将下面的代码复制粘贴到项目中
  3. 替换“这可能是你的文件!!!”具有大小大于或等于 READ_SIZE 宏的文件的文件路径
  4. 在调试模式下运行几次以读取重叠读取文件请求的平均时间
  5. 在 RELEASE 模式下运行几次以读取重叠读取文件请求的平均时间
  6. 比较平均时间...
#include <iostream>
#include <chrono>
#include <Windows.h>

#define READ_SIZE 400000000

int main()
{
    // init
    void* data = new unsigned char[READ_SIZE];

HANDLE file = CreateFileW(L"Here could be your file!!!", // set file path to file with size of READ_SIZE 
        GENERIC_READ,
        NULL,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
        NULL);

if (file == INVALID_HANDLE_VALUE)
    {
        std::cout << "failed to CreateFile!\n";
        std::cin.ignore();
        return 1;
    }

// request overlapped read
    OVERLAPPED overlapped{};
    
std::chrono::high_resolution_clock::time_point begin = std::chrono::high_resolution_clock::now();
    ReadFile(file, data, READ_SIZE, NULL, &overlapped);
    if (GetLastError() != ERROR_IO_PENDING)
    {
        std::cout << "failed to request overlapped file read\n";
        std::cin.ignore();
        return 1;
    }
    std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
    
int readFile_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();

// wait for overlapped read to complete
    begin = std::chrono::high_resolution_clock::now();
    DWORD bytesRead;
    GetOverlappedResult(file, &overlapped, &bytesRead, TRUE);
    end = std::chrono::high_resolution_clock::now();

int getOverlappedResult_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();

// print results
    std::cout << readFile_duration + getOverlappedResult_duration << "(ms) for " << bytesRead / 1000000 << "(mb)\n";
    std::cout << readFile_duration << "(ms) to request overlapped file read\n";
    std::cout << getOverlappedResult_duration << "(ms) for overlapped read to complete\n";

// cleanup
    CloseHandle(file);
    std::cin.ignore();
}

但是我认为他们不会很快解决这个问题,而且 8 毫秒对我来说似乎也是很多内核开销......我正在寻找的是某种方法来直接告诉驱动程序SSD/HDD/M2 等,在内核不减慢速度的情况下该怎么做。

我发现似乎有一种使用IRP(I/O Request Package)的方法:
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/handling-irps
然而,为了使用这些,我的代码必须在内核模式下运行,据我所知,这是一个非常糟糕的主意。

如果您可能知道是否有一种方法可以在 win32 中进行异步/重叠文件读取而无需太多内核开销,或者可能是某种与平台无关的方式,或者您可能能够为我指出一个新的方向,请这样做!

c++ winapi io overlapped-io
1个回答
0
投票

来自@Stuntman 给你的链接

用于读取和写入操作的文件访问缓冲区地址应该是物理扇区对齐的,这意味着内存中的地址是卷物理扇区大小的整数倍。

我不认为你正在这样做(并且你正在得到的对齐可能在调试和发布版本之间有所不同)。

根据磁盘的不同,可能不会强制执行此要求。

因此,考虑到上述情况,可能会产生次要影响(即缓冲区对齐),从而影响您的计时。

阅读手册和评论,伙计。

© www.soinside.com 2019 - 2024. All rights reserved.