【问题标题】:How to efficiently write a vector of structs to file?如何有效地将结构向量写入文件?
【发布时间】:2013-02-02 22:51:30
【问题描述】:

我的代码将大小大于 1000 万的向量写入文本文件。我使用 clock() 来计时 writefile 函数及其程序中最慢的部分。有没有比我下面的方法更好的写入文件的方法?

void writefile(vector<fields>& fieldsvec, ofstream& sigfile, ofstream& noisefile)
/* Writes clean and noise data to respective files
 *
 * fieldsvec: vector of clean data
 * noisevec: vector of noise data
 * sigfile: file to store clean data
 * noisefile: file to store noise data
 */
{
    for(unsigned int i=0; i<fieldsvec.size(); i++)
    {
        if(fieldsvec[i].nflag==false)
        {
            sigfile << fieldsvec[i].timestamp << ";" << fieldsvec[i].price << ";" << fieldsvec[i].units;
            sigfile << endl;
        }
        else
        {
            noisefile << fieldsvec[i].timestamp << ";" << fieldsvec[i].price << ";" << fieldsvec[i].units;
            noisefile << endl;
        }
    }
}

我的结构在哪里:

struct fields
// Stores a parsed line of a file
{
public:
    string timestamp;
    float price;
    float units;
    bool nflag; //flag if noise (TRUE=NOISE)
};

【问题讨论】:

  • 你可以回退到 fread/fwrite 的旧 C i/o 函数,看看是否更快?
  • 我打赌“fprintf()”会比ostream快很多——不幸的是,它需要一些重写,使用“FILE *”而不是“ost​​ream&”作为输入函数。

标签: c++ vector struct


【解决方案1】:

我建议摆脱endl。这样每次都有效地刷新缓冲区,从而大大增加了系统调用的数量。

'\n'而不是endl应该是一个很好的改进。

顺便说一句,代码可以简化:

ofstream& files[2] = { sigfile, noisefile };
for(unsigned int i=0; i<fieldsvec.size(); i++)
  files[fieldsvec[i].nflag] << fieldsvec[i].timestamp << ';' << fieldsvec[i].price << ";\n";

【讨论】:

  • @riotburn:我很想听听您使用未修改代码的计时结果,仅将std::endl 更改为'\n'。另请注意,ipc 推荐 character '\n',而不是 "\n"const char*。请让我们知道这种变化会带来什么样的不同!
  • 所以在进行任何更改之前,writefile 需要 107.8 秒。使用“\n”现在需要 41.8 秒!使用 '\n' 需要 40.63 秒。有什么不同! @ipc 我尝试使用您将文件存储在数组中的聪明想法,但出现以下错误:scrub.cpp:174:22: error: declaration of ‘files’ as array of reference
  • 我的虚拟机在打开一段时间后变得缓慢,所以我重新启动它,写入文件功能需要 35 秒。所以结果可能有点偏差,但它的对接加载速度更快。现在它是我最快的功能,所以我要努力加快读取和过滤功能。
【解决方案2】:

您可以按照the first answer of this SO question 中的建议以二进制格式而不是文本格式编写文件以提高写入速度:

file.open(filename.c_str(), ios_base::binary);
...
// The following writes a vector into a file in binary format
vector<double> v;
const char* pointer = reinterpret_cast<const char*>(&v[0]);
size_t bytes = v.size() * sizeof(v[0]);
file.write(pointer, bytes);

从同一链接,OP 报告:

  • 将 std::endl 替换为 \n 将代码速度提高了 1%
  • 将所有要写入的内容串联在一个流中,最后将所有内容写入文件中,代码速度提高了 7%
  • 将文本格式更改为二进制格式使他的代码速度提高了 90%。

【讨论】:

  • @riotburn:正如 Etienne 所建议的那样,您也非常想知道使用二进制 I/O 而非文本可以获得什么样的性能提升!请告诉我们!
  • 这是一个很好的建议,但不幸的是我必须将其保留为文本格式。谢谢!
【解决方案3】:

一个重要的速度杀手是您将数字转换为文本。

至于原始文件输出,ofstream 上的缓冲默认情况下应该非常有效。

您应该将数组作为 const 引用传递。这可能没什么大不了,但它确实允许某些编译器优化。

如果您认为流因为重复写入而搞砸了,您可以尝试使用sprintfsnprintf 创建一个字符串并写入一次。仅当您的时间戳是已知大小时才执行此操作。当然,这会产生额外的复制,因为必须将字符串放入输出缓冲区。实验。

否则,它会开始变脏。当您需要调整文件的性能时,您需要开始为您的应用程序定制缓冲区。这往往归结为不使用缓冲或缓存、对自己的缓冲区进行扇区对齐以及写入大块。

【讨论】:

    猜你喜欢
    • 2013-11-21
    • 2018-07-08
    • 2013-04-29
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多