为什么这个C++程序在Windows上比Linux慢?

Mat*_*hid 6 c++ windows io microbenchmark

考虑以下程序:

#define _FILE_OFFSET_BITS 64   // Allow large files.
#define REVISION "POSIX Revision #9"

#include <iostream>
#include <cstdio>
#include <ctime>

const int block_size = 1024 * 1024;
const char block[block_size] = {};

int main()
{
    std::cout << REVISION << std::endl;  

    std::time_t t0 = time(NULL);

    std::cout << "Open: 'BigFile.bin'" << std::endl;
    FILE * file;
    file = fopen("BigFile.bin", "wb");
    if (file != NULL)
    {
        std::cout << "Opened. Writing..." << std::endl;
        for (int n=0; n<4096; n++)
        {
            size_t written = fwrite(block, 1, block_size, file);
            if (written != block_size)
            {
                std::cout << "Write error." << std::endl;
                return 1;
            }
        }
        fclose(file);
        std::cout << "Success." << std::endl;

        time_t t1 = time(NULL);
        if (t0 == ((time_t)-1) || t1 == ((time_t)-1))
        {
            std::cout << "Clock error." << std::endl;
            return 2;
        }

        double ticks = (double)(t1 - t0);
        std::cout << "Seconds: " << ticks << std::endl;

        file = fopen("BigFile.log", "w");
        fprintf(file, REVISION);
        fprintf(file, "   Seconds: %f\n", ticks);
        fclose(file);

        return 0;
    }

    std::cout << "Something went wrong." << std::endl;
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

它只是将4GB的零写入磁盘上的文件并计算所需的时间.

在Linux下,平均需要148秒.在Windows下,在同一台PC上,平均需要247秒.

到底做错了什么?!

代码是在GCC for Linux和Visual Studio for Windows下编译的,但是我无法想象编译器使用的宇宙应该对纯I/O基准产生任何可测量的差异.在所有情况下使用的文件系统是NTFS.

我只是不明白为什么存在如此巨大的性能差异.我不知道为什么Windows运行这么慢.如何强制Windows以磁盘显然能够的全速运行?

(以上数字适用于旧戴尔笔记本电脑上的OpenSUSE 13.1 32位和Windows XP 32位.但我观察到办公室周围的几台PC上存在类似的速度差异,运行各种版本的Windows.)

编辑:可执行文件及其写入的文件都驻留在外部USB硬盘上,该硬盘格式为NTFS并且几乎完全为空.碎片几乎肯定不是问题.它可能是某种驱动程序问题,但我在运行不同版本Windows的其他几个系统上看到了相同的性能差异.没有安装防病毒软件.

只是为了咯咯笑,我尝试将其更改为直接使用Win32 API.(显然这只适用于Windows.)时间变得稍微不稳定,但仍然只是之前的百分之几.除非我指明FILE_FLAG_WRITE_THROUGH; 然后它变得非常慢.一些其他的标志使它变慢,但我找不到让它变得更快的那个...

sky*_*ing 0

您的测试并不是衡量性能的好方法,因为不同操作系统和库中的不同优化可能会产生巨大差异(编译器本身不必产生很大差异)。

首先,我们可以认为fwrite(或任何在 上运行的东西FILE*)是操作系统层之上的库层。不同的缓冲策略可能会产生不同的效果。例如,一种明智的实现方法fwrite是刷新缓冲区,然后将数据块直接发送到操作系统,而不是通过缓冲层。这可能会给下一步带来巨大的优势

其次,我们有可以以不同方式处理写入的操作系统/内核。一种明智的优化是通过仅对页面添加别名来复制页面,然后在别名之一发生更改时使用写入时复制。Linux 在向进程分配内存时(包括数组所在的 BSS 部分)已经(几乎)这样做了——它只是将页面标记为零,并且可以为所有这些页面保留一个这样的页面,然后在任何时候创建一个新页面有人在零页中进行了更改。再次执行此技巧意味着内核可以在磁盘缓冲区中为此类页面添加别名。这意味着在写入此类零块时,内核不会在磁盘缓存上运行不足,因为它只会占用 4KiB 的实际内存(页表除外)。如果数据块中有实际数据,则该策略也是可能的。

这意味着写入可以非常快速地完成,实际上不需要将任何数据传输到磁盘(fwrite完成之前),甚至不需要将数据从内存中的一个位置复制到另一个位置。

因此,您使用不同的库和不同的操作系统,它们在不同的时间执行不同的任务也就不足为奇了。