【问题标题】:All things equal what is the fastest way to output data to disk in C++?万事俱备,用 C++ 将数据输出到磁盘的最快方法是什么?
【发布时间】:2011-01-23 17:12:50
【问题描述】:

我正在运行很大程度上受 CPU 速度限制的模拟代码。我对将数据推入/推出用户界面不感兴趣,只需在计算时将其保存到磁盘。

降低开销的最快解决方案是什么? iostream?打印?我以前读过 printf 更快。这是否取决于我的代码,如果不进行分析就不可能得到答案吗?

这将在 Windows 中运行,输出数据需要为文本格式,制表符/逗号分隔,大多数浮点值具有格式/精度选项。

【问题讨论】:

  • 分析有什么问题?或者在你的情况下,只是时间安排?
  • 没什么,只是需要一个起点。
  • 最大化磁盘 IO 涉及很多细节,最好阅读一些已经完成分析的人的论文。
  • @Hassan 他们会为 OP 的特定应用程序进行分析,对吗?
  • @neil 几十年来人们一直在研究这个问题(如果我没记错的话是 3 个),应用程序是根据其 IO 特性进行分类的。所以是的......他应该能够找到一些关于如何优化他的用例的指南。

标签: c++ simulation


【解决方案1】:

构造(大)数据块,可以顺序写入并使用异步 IO。

准确分析会很痛苦,请阅读有关该主题的一些论文:scholar.google.com

【讨论】:

    【解决方案2】:

    我自己没有使用过它们,但我听说内存映射文件为操作系统提供了最佳优化机会。

    编辑:相关的 questionWikipedia article on memory mapped files — 都提到了性能优势。

    【讨论】:

    • 可惜没有可饮用的方式:( +1
    【解决方案3】:

    我的想法是你解决了错误的问题。为什么要写出大量的文本格式数据?如果是因为您希望它是人类可读的,那么编写一个快速的浏览器程序来动态读取二进制格式的数据 - 这样模拟应用程序可以快速写出二进制数据,浏览器可以完成格式化的繁重工作在需要时提供数据。如果是因为你正在使用一些统计包来读取和分析文本数据,那就写一个输入二进制数据的包。

    【讨论】:

      【解决方案4】:

      Scott Meyers 的更有效的 C++ 第 23 点“考虑备用库”如果您更喜欢速度而不是安全性和可扩展性,建议使用 stdio 而不是 iostream。值得一试。

      【讨论】:

        【解决方案5】:

        对于在典型目标操作系统和硬件上运行的特定应用程序而言,最快的方式是最快的。唯一明智的做法是尝试几种方法并为它们计时。您可能不需要完整的个人资料,并且练习应该只需要几个小时。我会按以下顺序进行测试:

        • 普通 C++ 流 I/O
        • 使用 ostream::write() 的普通流 I/O
        • 使用 C I/O 库
        • 使用系统调用,例如 write()
        • 异步 I/O

        当我找到足够快的解决方案时,我会停下来。

        【讨论】:

          【解决方案6】:

          文本格式意味着它是供人类使用的。人类阅读的速度远远低于任何合理输出方法的速度。某处有矛盾。我怀疑“输出必须是文本格式”。

          因此,我相信正确的是输出二进制文件,并提供单独的查看器将单个条目转换为可读文本。查看器中的格式设置只需与人们可以阅读的速度一样快。

          【讨论】:

            【解决方案7】:

            将文件映射到内存(即使用Memory Mapped File)然后只需memcopy-ing 数据,这是一种非常快速的读取/写入方式。

            您可以使用多个线程/内核来写入数据,操作系统/内核会将页面同步到磁盘,使用用于虚拟内存的相同类型的例程,可以期待优化到地狱并返回,或多或少。

            主要是,执行此操作时,内存中应该很少有额外的副本/缓冲区。写入被中断捕获并在写入页面后添加到磁盘队列中。

            【讨论】:

            • 这没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
            • @Jav_Rock:重写了答案,希望现在更好。
            【解决方案8】:

            以二进制模式打开文件,并将“未格式化”的数据写入光盘。

            fstream myFile;
            ...
            myFile.open ("mydata.bin", ios:: in | ios::out | ios::binary);
            ...
            class Data {
                int      key;
                double   value;
                char[10] desc;
            };
            
            Data x;
            
            myFile.seekp (location1);
            myFile.write ((char*)&x, sizeof (Data));
            

            编辑:OP 添加了“输出数据需要采用文本格式,无论是制表符还是逗号分隔。”约束。

            如果您的应用程序受 CPU 限制,则输出格式是您不需要的开销。二进制数据的读写速度比 ascii 快得多,在磁盘上更小(例如,使用二进制写入的总字节数比使用 ascii 少),并且由于它更小,因此在网络中移动更快(包括安装的网络文件系统)。所有指标都指向二进制作为一个很好的整体优化。

            可以在运行后使用一个简单的实用程序查看二进制数据,该实用程序会将数据以所需的任何格式转储到 ascii。我鼓励将一些版本信息添加到生成的二进制数据中,以确保可以在转储实用程序中处理数据格式的更改。

            从二进制迁移到 ascii,然后争论 printf 与 iostreams 的相对性能可能不是您时间的最佳利用方式。

            【讨论】:

              【解决方案9】:

              最快的方式是completion-based异步IO。

              通过向操作系统提供一组要写入的数据,当调用返回时它实际上并没有写入,操作系统可以对其重新排序以优化写入性能。

              执行此操作的 API 是特定于操作系统的:在 Linux 上,它称为 AIO;在 Windows 上,它称为 Completion Ports

              【讨论】:

                【解决方案10】:

                一种快速的方法是使用双缓冲和多线程(至少两个)。

                一个线程负责将数据写入硬盘。此任务检查缓冲区,如果不为空(或其他规则可能)开始写入硬盘。

                另一个线程将格式化文本写入缓冲区。

                硬盘驱动器的一个性能问题是加快速度并将磁头定位到正确位置所需的时间。为避免这种情况发生,目标是不断写入硬盘驱动器,使其不会停止。这很棘手,可能涉及程序范围之外的内容(例如同时运行的其他程序)。写入硬盘的数据块越大越好。

                另一个难题是在硬盘驱动器上找到用于放置数据的空插槽。碎片硬盘驱动器会比格式化或碎片整理的驱动器慢。

                如果可移植性不是问题,您可以检查您的操作系统是否有一些对硬盘执行块写入的 API。或者你可以往下走,使用直接写入驱动器的 API。

                您可能还希望您的程序更改其优先级,使其成为正在运行的最重要的任务之一。

                【讨论】:

                • 我不确定为 IO 添加线程是否正确。主要的计算循环受 CPU 限制。如果机器是多核的,那么更好的整体优化可能是将并行性添加到代码的计算部分。如果机器不是多核的,那么在主循环已经受 CPU 限制的情况下为 IO 添加线程可能不会增加应用程序的整体吞吐量。
                猜你喜欢
                • 1970-01-01
                • 2015-05-29
                • 2012-06-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-04-29
                • 1970-01-01
                • 2010-11-08
                相关资源
                最近更新 更多