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

Posted

技术标签:

【中文标题】为啥这个 C++ 程序在 Windows 上比在 Linux 上慢?【英文标题】:Why is this C++ program slower on Windows than Linux?为什么这个 C++ 程序在 Windows 上比在 Linux 上慢? 【发布时间】:2016-01-20 05:15:12 【问题描述】:

考虑以下程序:

#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;

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

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

我到底做错了什么?!

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

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

(上面的数字适用于旧戴尔笔记本电脑上的 OpenSUSE 13.1 32 位和 Windows XP 32 位。但我观察到办公室周围几台运行不同版本 Windows 的 PC 上的速度差异相似。)

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

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

【问题讨论】:

您能告诉我们文件系统吗?我猜是 ext4 和 NTFS,但最好确定一下。 @MathematicalOrchid 哈哈,为什么不试试 Windows 的 gcc 呢?底线是 fwrite 仍然依赖于编译器。 也许 xp 在没有适当的驱动程序的情况下运行,因此传输到磁盘的速度较慢。或防病毒软件干扰。或者 Linux 在写入之前在 RAM 中进行缓冲,Windows 先刷新,......等等......无论如何:对于任何不是来自石器时代的磁盘,连续写入速度低于 70 Mb/s 的所有内容都很慢跨度> 我假设“同一台 PC”意味着双启动,而不是相同的机器。假设是硬盘驱动器(不是 SSD),根据分区在驱动器上的物理位置,性能差异很大。早期的物理位置比后来的物理位置快得多。 获得良好的磁盘写入速度关键取决于文件的确切位置(外部磁道最好)、卷的碎片(导致磁盘寻道)和文件系统缓存可用的 RAM 量.这对于“旧戴尔笔记本电脑”来说肯定是不够的。仅仅文件位置就已经足以解释速度差异了。对磁盘进行碎片整理是 XP 上的一项手动维护任务。 【参考方案1】:

您需要将文件内容同步到磁盘,否则您只是在测量操作系统正在执行的缓存级别。

在关闭文件之前致电fsync

如果你不这样做,大部分的执行时间很可能会花在等待缓存被刷新以便可以在其中存储新数据,但你写入的数据的一部分肯定不会被写出在您关闭文件时到磁盘。那么,执行时间的差异可能是由于 linux 在可用缓存空间耗尽之前缓存了更多的写入。相反,如果您在关闭文件之前调用fsync所有写入的数据应该在您的时间测量发生之前刷新到磁盘。

我怀疑如果你添加一个fsync 调用,两个系统上的执行时间不会相差这么多。

【讨论】:

【参考方案2】:

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

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

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

这意味着写入可以非常快速完成,实际上不需要将任何数据传输到磁盘(在fwrite 完成之前),即使不需要从一个地方复制数据记忆中的另一个人。

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

【讨论】:

【参考方案3】:

对全为零的页面进行了特殊优化。你应该在写出之前用随机数据填充页面。

【讨论】:

好的,所以我尝试用随机数据填充数组。 (这一步不是时间的一部分。)写入文件仍然花费几乎完全相同的时间[在 Windows 上;我没有检查 Linux]。 我很确定仅写入 0 不足以在文件中创建稀疏区域。您需要使用特定于操作系统的调用/ioctls 或在文件末尾使用 ftruncateseek @MathematicalOrchid:问题在于 Linux 测量,这是您需要重做的测量。 (或者至少理论上是这样的。)

以上是关于为啥这个 C++ 程序在 Windows 上比在 Linux 上慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 sift.compute() 在 MSER 关键点上比在 SIFT 关键点上慢

SSE 程序在 AMD 上比在 Intel 上花费的时间要长得多

为啥这个算法在 python 中的运行速度比在 C++ 中快得多?

为啥在 VB.NET 中使用 DeviceIoControl 进行文件枚举比在 C++ 中更快?

简单的数学运算在 double 上比在 float 数据类型上更快? [复制]

Unity 应用在 IOS 上比在 Android 上使用更多的内存