我对 win32 ReadFile() 重叠 I/O 并不是很满意,因为它确实不可靠,并且在 DEBUG 配置中的内核开销为 8-10 毫秒,在 RELEASE 配置(Visual Studio)中为 400mb,内核开销为 25-30 毫秒,内核开销与读取的字节大小成正比...我已经报告了这一点: https://developercommunity.visualstudio.com/t/Overlapping-ReadFile-takes-significantly/10475365
重现步骤:
#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 中进行异步/重叠文件读取而无需太多内核开销,或者可能是某种与平台无关的方式,或者您可能能够为我指出一个新的方向,请这样做!
来自@Stuntman 给你的链接:
用于读取和写入操作的文件访问缓冲区地址应该是物理扇区对齐的,这意味着内存中的地址是卷物理扇区大小的整数倍。
我不认为你正在这样做(并且你正在得到的对齐可能在调试和发布版本之间有所不同)。
根据磁盘的不同,可能不会强制执行此要求。
因此,考虑到上述情况,可能会产生次要影响(即缓冲区对齐),从而影响您的计时。
阅读手册和评论,伙计。