提问人:Schrottiy 提问时间:10/9/2023 最后编辑:Schrottiy 更新时间:10/9/2023 访问量:132
没有内核开销的异步/重叠文件读取?
Asynchronous/Overlapped File Read without kernel overhead?
问:
我对 win32 ReadFile() 重叠的 I/O 并不真正感兴趣,因为它真的很不可靠,并且在 DEBUG 配置中具有 8-10 毫秒的令人不快的内核开销,在 25-30 毫秒的 RELEASE 配置(Visual Studio)中为 400 毫秒,内核开销与读取的字节大小有关......我已经报告了这个:https://developercommunity.visualstudio.com/t/Overlapping-ReadFile-takes-significantly/10475365
重现步骤:
- 在 Visual Studio 中创建新项目,然后选择“控制台应用”
- 将下面的代码复制粘贴到项目中
- 将“Here could be your file!!”替换为大于或等于 READ_SIZE 宏的文件路径
- 在 DEBUG 模式下运行几次,以读取重叠读取文件请求的平均时间
- 在 RELEASE 模式下运行几次,以读取重叠读取文件请求的平均时间
- 比较平均时间...
#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 请求包)的方法:
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/handling-irps
但是为了使用这些,我的代码必须在内核模式下运行,据我所知,这是一个非常糟糕的主意。
如果您知道是否有一种方法可以在 win32 中没有太多内核开销的异步/重叠文件读取,或者 maby 某种与平台无关的方式,或者您也许可以为我指出一个新的方向,请这样做!
答:
从@Stuntman给你的链接:
用于读取和写入操作的文件访问缓冲区地址应与物理扇区对齐,这意味着内存中的地址与卷的物理扇区大小的整数倍一致。
我不认为你正在这样做(你得到的对齐方式可能在调试和发布版本之间有所不同)。
根据磁盘的不同,可能不会强制执行此要求。
因此,鉴于上述情况,可能会有次要影响(即缓冲区对齐)影响您的时间。
但请参阅下面的@rbmm的评论。你仍然有一个对齐问题,只是不是我认为你有的问题。
评论
operator new
返回一个针对任何类型适当对齐的指针。
AlignmentRequirement
+ 1 上。
评论
ReadFile
ReadFile
ZwReadFile
FILE_FLAG_NO_BUFFERING