更快替代std :: ofstream

时间:2011-06-08 02:29:43

标签: c++ std fstream ofstream

我生成一组数据文件。由于文件应该是可读的,因此它们文本文件(与二进制文件相对)。

为了向我的文件输出信息,我使用了非常舒服的 std :: ofstream 对象。

一开始,当要导出的数据较小时,写入文件所需的时间不明显。但是,随着要导出的信息的累积,现在需要大约5分钟来生成它们。

当我开始被等待困扰时,我的问题很明显:是否有更快的替代std :: ofstream ,好吗?如果有更快的替代方案,是否值得重写我的应用程序?换句话说,节省的时间是+ 50%?谢谢。


更新

我被要求向您显示生成上述文件的我的代码,所以在这里 - 最耗时的循环

ofstream fout;
fout.open(strngCollectiveSourceFileName,ios::out);

fout << "#include \"StdAfx.h\"" << endl;
fout << "#include \"Debug.h\"" << endl;
fout << "#include \"glm.hpp\"" << endl;
fout << "#include \"" << strngCollectiveHeaderFileName.substr( strngCollectiveHeaderFileName.rfind(TEXT("\\")) + 1) << "\"" << endl << endl;

fout << "using namespace glm;" << endl << endl << endl;


for (unsigned int nSprite = 0; nSprite < vpTilesetSprites.size(); nSprite++ )
{
    for(unsigned int nFrameSet = 0; nFrameSet < vpTilesetSprites[nSprite]->vpFrameSets.size(); nFrameSet++)
    {

        // display index definition
        fout << "// Index Definition: " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetLongDescription() << "\n";
        string strngIndexSignature = strngIndexDefinitionSignature;
        strngIndexSignature.replace(strngIndexSignature.find(TEXT("#aIndexArrayName#")), strlen(TEXT("#aIndexArrayName#")), TEXT("a") + vpTilesetSprites[nSprite]->GetObjectName() + vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetFrameSetName() + TEXT("IndexData") );
        strngIndexSignature.replace(strngIndexSignature.find(TEXT("#ClassName#")), strlen(TEXT("#ClassName#")), strngCollectiveArrayClassName );        
        fout << strngIndexSignature << "[4] = {0, 1, 2, 3};\t\t" << "// " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetShortDescription() << ": Index Definition\n\n";


        // display vertex definition
        fout << "// Vertex Definition: " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetLongDescription() << "\n";

        string strngVertexSignature = strngVertexDefinitionSignature;
        strngVertexSignature.replace(strngVertexSignature.find(TEXT("#aVertexArrayName#")), strlen(TEXT("#aVertexArrayName#")), TEXT("a") + vpTilesetSprites[nSprite]->GetObjectName() + vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetFrameSetName() + TEXT("VertexData") );
        strngVertexSignature.replace(strngVertexSignature.find(TEXT("#ClassName#")), strlen(TEXT("#ClassName#")), strngCollectiveArrayClassName );
        fout << strngVertexSignature << "[" << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetFramesCount() << "] =\n";
        fout << "{\n";

        for (int nFrameNo = 0; nFrameNo < vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetFramesCount(); nFrameNo++)
        {
            fout << "\t" << "{{ vec4(" << fixed << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[0].vPosition.fx << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[0].vPosition.fy << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[0].vPosition.fz << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[0].vPosition.fw << "f), vec2(" << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[0].vTextureUV.fu << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[0].vTextureUV.fv << "f) },  // " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetShortDescription() << " vertex 1: vec4(x, y, z, w), vec2(u, v) \n";
            fout << "\t" << " { vec4(" << fixed << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[1].vPosition.fx << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[1].vPosition.fy << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[1].vPosition.fz << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[1].vPosition.fw << "f), vec2(" << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[1].vTextureUV.fu << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[1].vTextureUV.fv << "f) },  // " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetShortDescription() << " vertex 2: vec4(x, y, z, w), vec2(u, v) \n";
            fout << "\t" << " { vec4(" << fixed << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[2].vPosition.fx << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[2].vPosition.fy << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[2].vPosition.fz << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[2].vPosition.fw << "f), vec2(" << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[2].vTextureUV.fu << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[2].vTextureUV.fv << "f) },  // " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetShortDescription() << " vertex 3: vec4(x, y, z, w), vec2(u, v) \n";
            fout << "\t" << " { vec4(" << fixed << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[3].vPosition.fx << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[3].vPosition.fy << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[3].vPosition.fz << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[3].vPosition.fw << "f), vec2(" << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[3].vTextureUV.fu << "f, " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->vpFrames[nFrameNo]->aVertices[3].vTextureUV.fv << "f) }},  // " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetShortDescription() << " vertex 4: vec4(x, y, z, w), vec2(u, v) \n\n";
        }
        fout << "};\n\n\n\n";
    }
}

fout.close();

5 个答案:

答案 0 :(得分:4)

如果您不想使用C文件I / O,那么您可以尝试一下; FastFormat。查看比较以获取更多信息。

答案 1 :(得分:3)

假设你在足够大的块中执行它,直接调用write()可能会更快;也就是说,你最大的瓶颈更可能与std :: ofstream没有任何直接关系。最明显的是确保你没有使用std :: endl(因为频繁刷新流会杀死性能)。除此之外,我建议您分析您的应用,看看它实际花费的时间。

答案 2 :(得分:3)

vpTilesetSpritesvpTilesetSprites[nSprite]如何存储?它们是用列表还是数组实现的?有一个很多的索引访问权限,如果它们是类似列表的结构,你将花费大量额外的时间来跟随不必要的指针。 Ed S.的评论是对的:给出长索引的临时变量和换行符可以使它更容易阅读,也许更快:

fout << "// Index Definition: " << vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetLongDescription() << "\n";
string strngIndexSignature = strngIndexDefinitionSignature;
strngIndexSignature.replace(strngIndexSignature.find(TEXT("#aIndexArrayName#")), strlen(TEXT("#aIndexArrayName#")), TEXT("a") + vpTilesetSprites[nSprite]->GetObjectName() + vpTilesetSprites[nSprite]->vpFrameSets[nFrameSet]->GetFrameSetName() + TEXT("IndexData") );
strngIndexSignature.replace(strngIndexSignature.find(TEXT("#ClassName#")), strlen(TEXT("#ClassName#")), strngCollectiveArrayClassName );        

VS

string idxsig = strngIndexDefinitionSignature;
sprite sp = vpTilesetSprites[nSprite];
frameset fs = sp->vpFrameSets[nFrameSet];

fout << "// Index Definition: " << fs->GetLongDescription() << "\n";
idxsig.replace(idxsig.find(TEXT("#aIndexArrayName#")), strlen(TEXT("#aIndexArrayName#")),
    TEXT("a") + sp->GetObjectName() + fs->getFrameSetName() + TEXT("IndexData"));
idxsig.replace(idxsig.find(TEXT("#ClassName#")), strlen(TEXT("#ClassName#")),
    strngCollectiveArrayClassName);

但是,更大的问题是你如何使用字符串作为模板;您正在寻找给定的文本字符串(并且每次需要时计算 needle 字符串的长度!)一遍又一遍

请考虑以下事项:您正在执行查找和替换操作nSprite * nFrameSet次。每一次,这个循环:

  • 制作strngIndexDefinitionSignature
  • 的副本
  • 在连接静态和动态字符串时创建四个临时字符串对象
  • compute strlen(TEXT("#ClassName#"))
  • compute strlen(TEXT("#aIndexArrayName#"))
  • 找到两者的起点
  • 用新文本替换两个文本

这只是循环的前四行。

您可以使用格式字符串替换strngIndexDefinitionSignature吗?我认为它目前看起来像这样:

"flubber #aIndexArrayName# { blubber } #ClassName# blorp"

如果你像这样重写:

"flubber a %s%sIndexData { blubber } %s blorp"

然后你的两个查找和替换行可以替换为:

sprintf(out, index_def_sig, sp->GetObjectName(), fs->getFrameSetName(),
    strngCollectiveArrayClassName);

这将删除两个find()操作,两个replace()操作,创建和销毁四个临时字符串对象,一个字符串副本,通过两个replace()调用迅速覆盖,以及两个strlen()每次都返回相同结果的操作(但实际上并不需要)。

然后您可以像往常一样用<<输出字符串。或者,您可以将sprintf(3)更改为fprintf(3),并避免使用临时C字符串。

答案 3 :(得分:1)

ostream的表现可能不是您的实际问题;我建议使用分析器来确定您的真正瓶颈在哪里。如果ostream原来是您的实际问题,您可以下拉到<cstdio>并使用fprintf(FILE*, const char*, ...)格式化输出到文件句柄。

答案 4 :(得分:1)

最佳答案取决于您生成的文本类型以及生成方式。 C ++流可能很慢,但主要是因为它们还可以为您做更多的事情,例如依赖于语言环境的格式化等等。

您可以通过绕过某些格式(例如ostream::write)或直接将字符写入streambuf(streambuf::sputn)来查找带流的加速。有时增加相关streambuf上的缓冲区大小有助于(通过streambuf::pubsetbuf)。

如果这还不够好,您可能想尝试C风格的stdio文件,例如fopenfprintf等。需要一点时间来习惯文本的方式如果您不习惯该方法,则会被格式化,但性能通常非常好。

对于绝对顶级性能,您通常必须转到特定于操作系统的例程。有时直接的低级文件例程明显优于C stdio,但有时候没有 - 例如,我看到有人说Win32上的WriteFile是Windows上最快的方法,而一些谷歌命中报告它比STDIO。另一种方法可能是内存映射文件,例如。 mmap + msync - 这主要使用您的系统内存作为磁盘,并将实际数据以大块写入磁盘,这可能接近最佳状态。但是,如果由于某种原因导致中途崩溃,您可能会丢失所有数据,这对您来说可能是也可能不是问题。