【问题标题】:Writing huge 2D vectors to text file too slow, how to improve performance?将巨大的 2D 向量写入文本文件太慢,如何提高性能?
【发布时间】:2015-08-15 06:44:10
【问题描述】:

我有 10 个大型(3400 万个单元格)二维网格向量存储双精度数。写入时,它们的大小超过 200 mb。我使用 ofstream 对象将它们写入文本文件(csv 格式),一次一个元素,使用两个 for 循环(一个用于我的行,一个用于我的列)。他们需要很长时间才能写作。有没有更快的方法来写这些向量?

这是我的代码:

// Resizing of vectors
flowDirGrid.resize(rows, std::vector<double>(cols, NODATA));

// Do some processing
....

// Outputting processed data
ofstream outfile3("FlowDir.dat");
if(!outfile3.good())
    return;

for(int i=0; i<rows; i++)        
    {
        for (int j=0; j<cols; j++)
        {
            if(elevation[i][j]!=NODATA)
                outfile3 << flowDirGrid[i][j]<<" ";
            else
                outfile3 << NODATA<<" ";
        }
        outfile3 << std::endl;
    }

outfile3.close(); 

我正在使用 C++ 和 Visual Studio 2012。

编辑:。我已经删除了所有的 std::endl 实例并替换为 "\n",但仍然需要 17 分钟来编写每个输出文件。我可能会转而使用推荐的 C 方法。

使用三元而不是 if-else 阶梯会加快速度吗?

【问题讨论】:

  • 如果fstream 太慢,你可以测试是否使用较低级别的std::snprintf 到字符缓冲区,然后使用std::fwrite 将缓冲区内容写入速度加快。或者,如果您可以使用额外的库,您可以查看 The Boost Format library 并查看它们是否表现更好。
  • 太长是 10-20 分钟,具体取决于机器。有时,作为其中一部分的代码需要连续运行 10-100 次以校准处理功能。所以我在 1 次跑步中节省的每一分钟,在某些跑步中可以节省 10 到 100 分钟。
  • 您可以查看stackoverflow.com/a/11564931/19254codereview.stackexchange.com/q/80720/77127 看看他们是否有帮助。
  • 当输出看起来很慢时要做的第一件事就是只在最后刷新缓冲区,而不是在循环中。 std::endl 基本上是输出缓冲区的返回和刷新。
  • 如果您不需要使用不同大小的行的能力,请考虑使用连续数据结构

标签: c++ vector ofstream


【解决方案1】:

C++ iostream 库很方便,但速度很慢。 fprintf 会更好地为您服务。另外,请使用 '\n' 而不是 endl,因为后者会强制流刷新。


#include <cstdio>
#include <chrono>
#include <fstream>
#include <iostream>
#include <random>
#include <vector>

using namespace std;
using namespace std::chrono;

void PrintC(const double * data, size_t n, const char * path)
{
    FILE * f = fopen(path, "w");
    for (size_t i(0); i != n; ++i)
        fprintf(f, "%lf ", data[i]);
    fclose(f);
}

void PrintCpp(const double * data, size_t n, const char * path)
{
    ofstream f(path);
    for (size_t i(0); i != n; ++i)
        f << data[i] << ' ';
}

template<typename PrintT>
void Time(const vector<double> & data, PrintT Print, const char * path, const char * text)
{
    auto s = steady_clock::now();
    Print(data.data(), data.size(), path);
    auto f = steady_clock::now();

    cout << text << ": " << duration_cast<duration<double>>(f - s).count() << endl;
}

int main()
{
    vector<double> data(34000000);
    default_random_engine generator;
    uniform_real_distribution<double> distribution(0.0, 1.0);
    for (size_t i(0); i != data.size(); ++i)
        data[i] = distribution(generator);

    Time(data, PrintC,   "test1.dat", "c");
    Time(data, PrintCpp, "test2.dat", "c++");
}

Visual Studio 2013 Professional,发布配置:

c: 17.2682
c++: 32.0839

【讨论】:

  • 您的陈述大多是错误的。 iostream 可以和 C API 一样快。
  • 我敢打赌,通过关闭与 stdio (std::ios_base::sync_with_stdio(false)) 的同步,您会看到明显的加速。
  • 没有区别。查看标准库代码,它设置了一个名为_Sync 的标志,实际上并没有在任何地方使用。
【解决方案2】:

20 分钟 200 MB 似乎真的长。您遇到了性能问题,因此您必须按顺序测试元素。

  1. 取一个 200 mb 并复制它(直接在操作系统级别)。如果需要大约 10 分钟,瓶颈就在这里:购买更快的磁盘

  2. 制作一个测试程序,生成一个 随机 值集(并非全为 0。因为 0. 比其他双精度值更容易转换,所以只是 * 不同的值),编写时间(至少包括秒)使用上面的代码写入文件并再次写入时间 - 或者,您可以使用当前代码只需添加两次。运行几次。如果比第一次测试花费的时间明显更长,请在此处报告第一次测试和第二次测试的时间。

  3. 如果上述测试都没有花费大约 10 分钟,则问题出在剩余代码中...

【讨论】:

    【解决方案3】:

    根据this answer std::endl 导致刷新流。尝试改用\n

    【讨论】:

      猜你喜欢
      • 2012-08-09
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      相关资源
      最近更新 更多