C++ 非常快速的文本文件处理(C+;+;)

C++ 非常快速的文本文件处理(C+;+;),c++,file,text,getline,C++,File,Text,Getline,我写了一个在GPU上处理数据的应用程序。代码运行良好,但我有一个问题,即输入文件的读取部分(~3GB,文本)是我的应用程序的瓶颈。(从硬盘读取速度快,但逐行处理速度慢) 我用getline()读取一行,将第1行复制到向量,将第2行复制到向量,并跳过第3行和第4行。其他1100万条生产线也是如此 我尝试了几种方法以尽可能在最佳时间获取文件: 我发现的最快的方法是使用boost::iostreams::stream 其他是: 将文件读取为gzip,以最小化IO,但速度比直接读取慢 读它 通过读取将

我写了一个在GPU上处理数据的应用程序。代码运行良好,但我有一个问题,即输入文件的读取部分(~3GB,文本)是我的应用程序的瓶颈。(从硬盘读取速度快,但逐行处理速度慢)

我用getline()读取一行,将第1行复制到向量,将第2行复制到向量,并跳过第3行和第4行。其他1100万条生产线也是如此

我尝试了几种方法以尽可能在最佳时间获取文件:

我发现的最快的方法是使用boost::iostreams::stream

其他是:

  • 将文件读取为gzip,以最小化IO,但速度比直接读取慢 读它
  • 通过读取将文件复制到ram(文件指针、字符、长度) 并使用循环处理以区分线条(也比boost慢)
有什么建议可以让它跑得更快吗

void readfastq(char *filename, int SRlength, uint32_t blocksize){
    _filelength = 0; //total datasets (each 4 lines)
    _SRlength = SRlength; //length of the 2. line
    _blocksize = blocksize;

    boost::iostreams::stream<boost::iostreams::file_source>ins(filename);
    in = ins;

    readNextBlock();
}


void readNextBlock() {
    timeval start, end;
    gettimeofday(&start, 0);

    string name;
    string seqtemp;
    string garbage;
    string phredtemp;

    _seqs.empty();
    _phred.empty();
    _names.empty();
    _filelength = 0;

            //read only a part of the file i.e the first 4mio lines
    while (std::getline(in, name) && _filelength<_blocksize) {
        std::getline(in, seqtemp);
        std::getline(in, garbage);
        std::getline(in, phredtemp);

        if (seqtemp.size() != _SRlength) {
            if (seqtemp.size() != 0)
                printf("Error on read in fastq: size is invalid\n");
        } else {
            _names.push_back(name);

            for (int k = 0; k < _SRlength; k++) {

                //handle special letters
                                    if(seqtemp[k]== 'A') ...
                                    else{
                _seqs.push_back(5);
                                    }

            }
            _filelength++;
        }
    }

显然,您使用的是
,因为您使用的是
getline

可能
fopen
-ing文件与
fopen(路径,“rm”)
可能会有所帮助,因为
m
告诉(它是GNU扩展)使用
mmap
进行读取

也许用
setbuffer
设置一个大缓冲区(即半兆字节)也会有所帮助

也许,使用系统调用(可能在单独的线程中)会有所帮助


但所有这些都是猜测。您应该真正测量事物。

首先,您可以使用文件映射,而不是将文件读入内存。您只需将程序构建为64位,以适应3GB的虚拟地址空间(对于32位应用程序,在用户模式下只能访问2GB)。或者,您也可以按部分映射和处理文件

接下来,我觉得您的瓶颈是“将直线复制到向量”。处理向量涉及到动态内存分配(堆操作),这在关键循环中会严重影响性能)。如果是这种情况-要么避免使用向量,要么确保它们在循环之外声明。后者有帮助,因为当您重新分配/清除向量时,它们不会释放内存

发布您的代码(或部分代码)以获取更多建议

void readfastq(char *filename, int SRlength) {
    _filelength = 0;
    _SRlength = SRlength;

    size_t bytes_read, bytes_expected;

    FILE *fp;
    fp = fopen(filename, "r");

    fseek(fp, 0L, SEEK_END); //go to the end of file
    bytes_expected = ftell(fp); //get filesize
    fseek(fp, 0L, SEEK_SET); //go to the begining of the file

    fclose(fp);

    if ((_seqarray = (char *) malloc(bytes_expected/2)) == NULL) //allocate space for file
        err(EX_OSERR, "data malloc");


    string name;
    string seqtemp;
    string garbage;
    string phredtemp;

    boost::iostreams::stream<boost::iostreams::file_source>file(filename);


    while (std::getline(file, name)) {
        std::getline(file, seqtemp);
        std::getline(file, garbage);
        std::getline(file, phredtemp);

        if (seqtemp.size() != SRlength) {
            if (seqtemp.size() != 0)
                printf("Error on read in fastq: size is invalid\n");
        } else {
            _names.push_back(name);

            strncpy( &(_seqarray[SRlength*_filelength]), seqtemp.c_str(), seqtemp.length()); //do not handle special letters here, do on GPU

            _filelength++;
        }
    }
}
编辑:

似乎所有的瓶颈都与字符串管理有关

  • std::getline(in,seqtemp)读入
    std::string
    处理动态内存分配
  • \u名称。向后推(名称)这更糟。首先,通过值将
    std::string
    放入
    向量中。表示-复制字符串,因此会发生另一个动态分配/释放。此外,当
    向量
    最终在内部重新分配时,所有包含的字符串将再次复制,并产生所有后果
我建议既不要使用标准格式的文件I/O函数(Stdio/STL),也不要使用
std::string
。为了获得更好的性能,应该使用指向字符串(而不是复制的字符串)的指针,如果映射整个文件,这是可能的。此外,您还必须实现文件解析(划分为行)

与此代码类似:

class MemoryMappedFileParser
{
    const char* m_sz;
    size_t m_Len;

public:

    struct String {
        const char* m_sz;
        size_t m_Len;
    };

    bool getline(String& out)
    {
        out.m_sz = m_sz;

        const char* sz = (char*) memchr(m_sz, '\n', m_Len);
        if (sz)
        {
            size_t len = sz - m_sz;

            m_sz = sz + 1;
            m_Len -= (len + 1);

            out.m_Len = len;

            // for Windows-format text files remove the '\r' as well
            if (len && '\r' == out.m_sz[len-1])
                out.m_Len--;
        } else
        {
            out.m_Len = m_Len;

            if (!m_Len)
                return false;

            m_Len = 0;
        }

        return true;
    }

};
一般性建议:

  • 编写最简单、最直接、干净的方法
然后,如果所有其他方法都失败了:

  • 读取页面对齐块中的原始字节()。按顺序执行,这样内核的预读就对您有利
  • 重复使用相同的缓冲区以最小化缓存刷新
  • 避免复制数据、就地解析、传递指针(和大小)

-另一种方法是复制文件的[部分]。这也避免了内核用户区拷贝。

如果
\u-seq
\u-names
std::vectors
,并且在处理整个3GB数据之前可以猜测它们的最终大小,那么可以使用它来避免在回推循环中的新元素时重新分配大部分内存


您应该知道这样一个事实,即向量有效地在主内存中生成文件部分的另一个副本。因此,除非您的主内存足够大,可以存储文本文件、向量及其内容,否则最终可能会出现大量页面错误,这些错误也会对程序的速度产生重大影响。

根据您的磁盘速度,使用非常快的反压缩算法可能会有所帮助,如fastlz(至少还有另外两种可能更有效,但根据GPL,所以许可证可能是个问题)

<> P>也可以使用C++的数据结构和函数来增加速度,这样可以实现更好的编译时间优化。C方式并不总是固定的!在一些坏的情况下,使用char *需要解析整个字符串,以达到0个屈服的性能。
对于解析数据,使用boost::spirit::qi可能也是最优化的方法。

通过“ram”您指的是PC ram或车载视频内存?请注意,和是对容器状态的只读测试。也许您指的是
.clear()
?可能重复的
\seqs.empty()
只返回
true
。默认构造函数创建一个空字符串,
bool std::string::empty()const
void std::string::clear()不同。我不知道你在解决的问题,但是你确定文本文件是用这样一个大的数据集和一个明显的时间关键的应用程序的方法吗?也有C++中的函数。我不同意。我认为它可以用标准库来写得很好(但是OP没有为上下文提供足够的代码)。.通过上述操作,您只会使代码变得非常脆弱。我不知道您所说的“脆弱”是什么意思。代码要么正确,要么不正确。但是,我不坚持。如果您有一个“标准”库/函数可以做同样的事,那么“脆弱”就是ea