流解析算法速度问题

stream parsing algorithm speed issue

本文关键字:速度 问题 算法      更新时间:2023-10-16

我写了一个波前 Obj 解析器类,用于将 obj 模型导入我的 OpenGL 项目。 我在调试模式下测试了该类,发现它慢得令人难以忍受。

代码有效,我进行了明显的调整,以确保它与合理实用的效率一样高。

尽管如此,加载我的测试文件,一个 12mb obj 文件,运行到大约 330,000 行文本,需要一分钟多的时间来解析。

沮丧的是,我有一个谷歌,果然,我不是第一个遇到这个问题的人。

这个在 gamedev.net 上发布查询的家伙只是在发布模式下运行他的算法,在Visual Studio IDE和whammo之外,性能可以接受。 这也对我有用,我的~70秒减少到~3秒。

我对算法进行了一些分析,瓶颈在于对 std::getline 的调用,以及以下内容:

sstream >> sToken;
其中 sstream 是 std::

stringstream,sToken 是 std::string(预先保留空格(。

问题

为什么 IDE 在运行

我的解析算法时如此慢得令人难以置信(即使在发布模式下( - 在通过 IDE 运行代码时,我能做些什么来加快速度(F5 - 运行项目(? 这使得调试变得非常慢。 IDE 是将代码/钩子注入可执行文件以通过 IDE 运行,还是可以将其归结为缓存未命中或其他原因?

优化

通过文件进行了两次传递,在第一次传递中,我只计算令牌类型 - 以便我可以保留空间(而不是迭代增长存储顶点、法线、texcoord、面等的向量(

sLineBuffer.reserve( 100 );
sToken.reserve(10);
while( sstream.good() )
{
    sstream >> sToken;
    getline( sstream, sLineBuffer );
    if( sToken.compare("f") == 0 )
        nFaces ++;
    else if( sToken.compare("v") == 0 )
        nVertices ++;
    else if( sToken.compare("vn") == 0 )
        nNormals ++;
    else if( sToken.compare("vt") == 0 )
        nTextures ++;
    else if( sToken.compare("g") == 0 )
        nGroups ++;
}
m_Vertices.reserve( nVertices );
m_Normals.reserve( nNormals );
m_TexCoords.reserve( nTextures );
m_Faces.reserve( nFaces );
m_Groups.reserve( nGroups );

第一次传递的成本很低(调试模式下为 ~8 秒,在 IDE 外部的发布模式下为 ~0.3 秒(,并且效率节省巨大(将解析时间从调试模式下的 ~180 秒减少到 ~60 秒(。

我还将整个文件读入字符串流,以便将磁盘访问从等式中剔除:

// Read entire file from disk into memory
fstream stream;
stringstream sstream;
stream.open( m_sFilename.c_str(), std::ios::in );
sstream << stream.rdbuf();
stream.close();

此外,在可能的情况下,在整个算法中,我尝试提前为 std::string 保留空间,以便它们不会按字符调整大小:

sLineBuffer.reserve( 100 );
sToken.reserve(10);  // etc
这个问题被

证明是对Visual Studio IDE运行方式的误解。

按 F5 将在调试模式下运行,无论你是在调试还是发布版本中。

我了解了 Ctrl+F5 将调试器从等式中取出的内容(但只有当您运行发布版本时,您才会在执行此操作时看到速度提高(。

我还了解到,在这种情况下,stdio 可能是一个更好的解决方案。 我将不得不按照建议重写我的算法以使用 fscanf,并在此处报告我的发现,尽管我对这个想法感到畏缩。

STL 的编写方式是期望编译器对许多小函数进行大量内联。不过,调试器允许您进入所有精彩的抽象层,并且在调试模式下您为此付出了高昂的代价,因为它无法内联任何内容。

通常我不会给出以下建议,但在解析 OBJ 文件的上下文中,我建议只扔掉 STL 并依靠老式的 fscanf 语句。您会发现在调试期间有显著的提高,在发布模式下速度也有明显的提高。