提问人:Smeghead 提问时间:7/23/2021 最后编辑:MgetzSmeghead 更新时间:7/23/2021 访问量:283
Microsoft 中的 C++ 标准库文件流操作是否瘫痪?
Are the C++ Standard Library File stream operations crippled in Microsoft?
问:
我之所以问这个问题,是因为我一直在做一个需要非常快速地收集大量数据的项目,具体取决于场景。5.7GBytes,大写字节/秒或11.4GB/秒。
我们正在使用 3 个 Samsung Pro NVME 使用小型条纹 raid 阵列(对于 11.4GB/s,我们有一个更大的阵列)。
目前,该项目已在 Windows 上开发,我想使事情尽可能可移植,所以我专注于使用 C++ 标准库;但是,无论我做什么,我都无法破解传输文件的速度超过1.5GB/s
该策略很简单,就是创建几个巨大的交换缓冲区,并将它们作为一个巨大的未格式化二进制文件直接写入磁盘。
通过以下方式使用和基准测试手动设置不同的缓冲区大小:std::ofstream
rdbuf()->pubsetbuf(buffer, BUFFER_SIZE);
open(Filename, std::ios::binary|std::ios::trunc);
其次是我的托管写入循环,我能够找到一个最佳位置,但始终无法破解 1.5GB/s
然后,我找到了 Windows SDK 及其 CreateFile 函数
特别是,使用 FILE_FLAG_NO_BUFFERING 标志的 create file 函数。
这是一个游戏规则的改变者,只要我确保我向它提供扇区对齐的数据(在我的情况下,一切都需要是 512Bytes 的倍数),我突然能够充分利用 raid 阵列吞吐量。
我重新审视了该函数,试图使用更多与操作系统无关的函数;但是,即使可以指定零缓冲区,似乎也没有任何关于在没有缓冲区的情况下使用该函数的任何警告的文档。std::ofstream
std::ofstream
std::ofstream
允许其写入大小为 64 位值,与仅接受 DWORD 设置的 Windows SDK WriteFile 不同,最大写入大小是 512 的最大倍数,如果文件超过 4GB,则必须在循环中管理写入(我的 DO)。uint32_t
这就提出了一个问题,Microsoft 是否根本没有让 C++ 标准库开发人员访问必要的操作系统级系统调用以利用超高速驱动器阵列?还是我在如何充分利用 C++ 标准库方面遗漏了一些东西?
答:
“Microsoft 只是不给 C++ 标准库开发人员......”
你可能会注意到,你正在使用的产品称为 Microsoft Visual Studio。Visual Studio 的标准库开发人员在 Microsoft 工作,尽管与 Windows 开发人员在不同的团队中工作。
原因更简单一些:Visual C++开发人员不可能了解和优化所有可能的使用场景。以如此高的速度进行文本格式设置有点不寻常。请记住,重点是提供. 用于格式化输出到文件。但是对于高速 I/O,无论如何您都需要二进制输出。ostream
operator<<
ofstream
评论
fstream
fstream
不会因为 studio.h 而变慢。 由于 .在 GitHub 上发布通用 CRT 后,您可以分析一些证据。fstream
fstream
坦率地说,你所瞄准的带宽在当前商用硬件的物理极限范围内(16×PCIe.4 为 ~24GByte/s),在我自己的工作中,我发现在不使用“暗魔法”(又名手工制作组装和优化的系统调用代码)的情况下达到 8GByte/s 以上的单核内存传输速率非常具有挑战性, 它涉及仔细对齐内存访问和利用向量扩展。但最重要的是,要达到这些优化级别,需要了解正在处理的数据类型以及预期的访问模式和/或构建缓存中介以适应底层硬件。
这种优化是显而易见的,完全超出了通用标准库的范围。标准库在其实现中必须遵守规范中记载的行为,其中一些要求往往与充分利用底层硬件所必须做的事情相冲突。
所以我很抱歉告诉你,但你可能不得不咬紧牙关,直接使用低级系统 API,绕过标准库。
评论
restrict
iostream
ReadFile
WriteFile
read
write
评论
std::format
CreateFile
fstream