逐行分析CMemFile中的文本

Parsing text from CMemFile line by line

本文关键字:文本 CMemFile 逐行      更新时间:2023-10-16

我已经将一个巨大的文本文件加载到CMemFile对象中,并希望逐行解析它(用换行符分隔)
最初,它是磁盘上的一个zip文件,我将它解压缩到内存中进行解析,因此就是CMemFile。

逐行读取的一种工作方法是(m_file是指向CMemFile的智能指针):

    CArchive archive(m_file.get(), CArchive::load);
    CString line;
    while(archive.ReadString(line))
    {
        ProcessLine(string(line));
    }

由于这需要很多时间,我尝试编写自己的例程:

    const UINT READSIZE = 1024;
    const char NEWLINE = 'n';
    char readBuffer[READSIZE];
    UINT bytesRead = 0;
    char *posNewline = NULL;
    const char* itEnd = readBuffer + READSIZE;
    ULONGLONG currentPosition = 0;
    ULONGLONG newlinePositionInBuffer = 0;
    do
    {
        currentPosition = m_file->GetPosition();
        bytesRead = m_file->Read(&readBuffer, READSIZE);        
        if(bytesRead == 0) break; // EOF
        posNewline = std::find(readBuffer, readBuffer + bytesRead, NEWLINE);
        if(posNewline != itEnd)
        {
            // found newline
            ProcessLine(string(readBuffer, posNewline));
            newlinePositionInBuffer = posNewline - readBuffer + 1; // +1 to skip r
            m_file->Seek(currentPosition + newlinePositionInBuffer, CFile::begin);
        }
    } while(true);

测量性能表明,这两种方法需要大约相同的时间。。。

你能想出任何性能改进或更快的解析方法吗

感谢您的任何建议

一些可能有用的注释和注释:

  • 分析是确定代码在做什么以及需要多长时间的唯一方法。通常,从代码本身来看,瓶颈并不明显。一个基本方法是分别对加载、解压缩和解析进行计时
  • 从磁盘实际加载文件,以及在您的情况下进行解压缩,实际上可能比解析花费更多的时间,尤其是如果您的ProcessFile()函数是nop。如果你的解析只需要总时间的1%,那么你永远不会从优化这1%中得到太多。这是分析代码会告诉你的
  • 优化加载/解析算法的一种通用方法是查看特定字节的读取/解析次数。最小的,可能也是最快的,算法必须只读取和解析每个字节一次。看看你的算法,每个字节似乎被复制了六次,并可能解析出类似的数字。减少这些数字可能有助于减少总体算法时间,尽管总体上相对增益可能不多

使用探查器显示75%的处理时间浪费在这行代码中:

 ProcessLine(string(readBuffer, posNewline));

主要是临时字符串的创建造成了很大的开销(许多分配)。ProcessLine函数本身不包含任何代码。通过将声明从更改为:

void ProcessLine(const std::string &);

至:

inline void ProcessLine(const char*, const char*);

所用的处理时间减少了五倍。

您可以在单独的线程中运行解压缩和解析。每次解压缩产生一些数据时,都应该使用消息机制将其传递给解析线程进行解析。

这允许两者并行运行,也会导致较小的内存开销,因为您在块中工作,而不是在整个解压缩文件中工作(这将减少页面错误和到虚拟内存的交换)。

我认为您的问题可能是您读得太多,并重新设置为新行。

如果你的文件是

   foo
   bar
   etc

平均每行10个字节。你将阅读10行。。。并再次读取这9行。