简体   繁体   English

为什么 std::fstream 在 Windows 上比 WriteFile 快

[英]Why is std::fstream faster than WriteFile on Windows

I have tried all sorts of different combinations of flags such as FILE_FLAG_NO_BUFFERING and FILE_FLAG_OVERLAPPED, but fstream::write still beats the Windows API version.我尝试了各种不同的标志组合,例如 FILE_FLAG_NO_BUFFERING 和 FILE_FLAG_OVERLAPPED,但fstream::write仍然胜过 Windows API 版本。

Does std::fstream use internal buffering or other tricks or am I just messing up something? std::fstream是否使用内部缓冲或其他技巧,或者我只是搞砸了什么?

#include <Windows.h>
#include <chrono>
#include <fstream>
#include <iostream>

std::string createTempFileName()
{
    char buf[800];
    tmpnam_s(buf, sizeof(buf));
    return buf;
}

using namespace std::chrono;

int main()
{
    std::uint64_t count = 1 << 23;

    std::cout << "test fstream\n";
    {
        auto start = steady_clock::now();
        auto path = createTempFileName();
        std::fstream fs(path, std::ios_base::out | std::ios_base::in | std::ios_base::trunc | std::ios_base::binary);
        for (std::uint64_t i = 0; i < count; i++)
            fs.write((char*)&i, sizeof(i));
        fs.close();
        DeleteFile(path.c_str());
        auto end = steady_clock::now();
        std::cout << "fstream: Elapsed time in milliseconds : " << duration_cast<milliseconds>(end - start).count() << " ms\n";
    }

    std::cout << "test WriteFile\n";
    {
        auto start = steady_clock::now();
        auto path = createTempFileName();
        HANDLE file = CreateFile(path.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, NULL);
        for (std::uint64_t i = 0; i < count; i++)
            WriteFile(file, &i, sizeof(i), NULL, NULL);
        CloseHandle(file);
        DeleteFile(path.c_str());
        auto end = steady_clock::now();
        std::cout << "WriteFile: Elapsed time in milliseconds : " << duration_cast<milliseconds>(end - start).count() << " ms\n";
    }
}

I suppose the obvious answer is to look at the source shipped with Visual Studio but since you chose not to do that, let us use our magic thinking hats instead.我想显而易见的答案是查看 Visual Studio 附带的源代码,但既然您选择不这样做,那么让我们改用我们神奇的思考帽。

There are not that many documented ways to write to a file on Windows and the C/C++ run-time will be using some Windows API to write.在 Windows 上写入文件的记录方法并不多,C/C++ 运行时将使用一些 Windows API 进行写入。 Ranked by popularity I would guess we are looking at WriteFile , memory mapped files and IStream .按受欢迎程度排名,我猜我们正在查看WriteFile 、内存映射文件和IStream IStream is COM and too high level. IStream是 COM 并且级别太高。 Memory mapped files are annoying when you don't know the final size so WriteFile is the most likely candidate.当您不知道最终大小时,内存映射文件很烦人,因此WriteFile是最有可能的候选者。

WriteFile does some minor work in user mode but at the end of the day it is going to end up with a context switch to kernel mode. WriteFile在用户模式下做了一些小工作,但最终它会以上下文切换到内核模式结束。

In your loop you are only writing 8 bytes every time and therefore a really large part of the CPU time is going to be spent switching in and out of kernel mode and whatever buffering the kernel (and storage hardware) is doing for this file handle does not prevent that.在您的循环中,您每次只写入 8 个字节,因此 CPU 时间的很大一部分将用于切换内核模式以及内核(和存储硬件)为此文件句柄所做的任何缓冲不阻止。

You are passing the FILE_FLAG_NO_BUFFERING flag to CreateFile yet fail to do any of the required work to make these writes aligned and you fail to check the return value of WriteFile !您正在将FILE_FLAG_NO_BUFFERING标志传递给CreateFile但未能执行任何使这些写入对齐所需的工作,并且您未能检查WriteFile的返回值! It might be failing and this entire test could be invalid for all we know.它可能会失败,并且整个测试可能对我们所知的所有内容都无效。

The C/C++ run-time is often willing to choose speed over size/memory usage and the magic word here is buffering. C/C++ 运行时通常愿意选择速度而不是大小/内存使用,这里的魔法词是缓冲。 Even a tiny 16 byte buffer would probably almost double your speed in this specific instance.在这种特定情况下,即使是一个很小的 ​​16 字节缓冲区也可能几乎使您的速度翻倍。 You can try to turn off this buffering with something like this:您可以尝试使用以下方法关闭此缓冲:

std::fstream fs;
fs.rdbuf()->pubsetbuf(NULL, 0);
fs.open(...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM