c++ - 大csv文件c++解析性能

标签 c++ csv stl io

我有一个代表对称图(约 18kX18k)的大 csv 文件(25 mb)。在将其解析为 vector 数组时,我分析了代码(使用 VS2012 ANALYZER),它表明在读取每个字符(getline::basic_string::operator+=)时出现解析效率问题(总共约 19 秒)如下图:enter image description here

这让我很沮丧,因为使用 Java 简单的缓冲行文件读取和标记器,我在不到半秒的时间内就实现了它。

我的代码只使用 STL 库:

int allColumns = initFirstRow(file,secondRow);
// secondRow has initialized with one value
int column = 1; // dont forget, first column is 0
VertexSet* rows = new VertexSet[allColumns];
rows[1] = secondRow;
string vertexString;
long double vertexDouble;
for (int row = 1; row < allColumns; row ++){
    // dont do the last row
    for (; column < allColumns; column++){
        //dont do the last column
        getline(file,vertexString,','); 
        vertexDouble = stold(vertexString);
        if (vertexDouble > _TH){
            rows[row].add(column);
        }
    }
    // do the last in the column
    getline(file,vertexString);
    vertexDouble = stold(vertexString);
    if (vertexDouble > _TH){
        rows[row].add(++column);
    }
    column = 0;
}
initLastRow(file,rows[allColumns-1],allColumns);

init 第一行和最后一行基本上和上面的循环做同样的事情,但是 initFirstRow 也会计算列数。

VertexSet 基本上是一个索引 vector (int)。每个读取的顶点(由“,”分隔)的长度不超过 7 个字符(值介于 -1 和 1 之间)。

最佳答案

25 兆字节,我猜你的文件是机器生成的。因此,您(可能)不需要担心诸如验证格式之类的事情(例如,每个逗号都已到位)。

鉴于文件的形状(即每一行都很长),您可能不会通过将每一行放入 stringstream 来解析数字而产生大量开销。

基于这两个事实,我至少会考虑编写一个将逗号视为空格的 ctype facet,然后使用该 facet 为 stringstream 注入(inject)一个语言环境,以便于解析数字。整体代码长度会稍长一些,但代码的每一部分最终都会非常简单:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <time.h>
#include <stdlib.h>
#include <locale>
#include <sstream>
#include <algorithm>
#include <iterator>

class my_ctype : public std::ctype<char> {
    std::vector<mask> my_table;
public:
    my_ctype(size_t refs=0):
        my_table(table_size),
        std::ctype<char>(my_table.data(), false, refs) 
    {
        std::copy_n(classic_table(), table_size, my_table.data());
        my_table[',']=(mask)space;
    }
};

template <class T>
class converter {
    std::stringstream buffer;
    my_ctype *m;
    std::locale l;
public:
    converter() : m(new my_ctype), l(std::locale::classic(), m) { buffer.imbue(l); }

    std::vector<T> operator()(std::string const &in) {
        buffer.clear();
        buffer<<in;
        return std::vector<T> {std::istream_iterator<T>(buffer),
            std::istream_iterator<T>()};        
    }
};

int main() {
    std::ifstream in("somefile.csv");
    std::vector<std::vector<double>> numbers;

    std::string line;
    converter<double> cvt;

    clock_t start=clock();
    while (std::getline(in, line))
        numbers.push_back(cvt(line));
    clock_t stop=clock();
    std::cout<<double(stop-start)/CLOCKS_PER_SEC << " seconds\n";
}

为了测试这一点,我生成了一个 1.8K x 1.8K 的伪随机 double CSV 文件,如下所示:

#include <iostream>
#include <stdlib.h>

int main() {
    for (int i=0; i<1800; i++) {
        for (int j=0; j<1800; j++)
            std::cout<<rand()/double(RAND_MAX)<<",";
        std::cout << "\n";
    }
}

这产生了一个大约 27 兆字节的文件。使用 gcc (g++ -O2rash9.cpp) 编译读取/解析代码后,在我的笔记本电脑上进行的快速测试显示它在大约 0.18 到 0.19 秒内运行。它似乎从未使用(甚至接近)所有一个 CPU 内核,这表明它受 I/O 限制,因此在台式机/服务器机器(具有更快的硬盘驱动器)上,我希望它运行得更快。

关于c++ - 大csv文件c++解析性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20815419/

相关文章:

linux - 如何从 Bash 将配对数字列表导出到 .csv 文件?

c++ - 如何返回带有私有(private)比较器的 std::set

c++ - Visual Studio 2010 Express STL列表编译器错误

c++ - 替换二维 vector C++ 中的数据

c++ - 没有 ntohs 的字节顺序交换

c++ - 如何获取pcl :PolygonMesh object的指针

scala - 无法覆盖 Spark 2.x 中 CSV 文件的架构

c++ - 从 C-Style-Array 释放内存

python - pandas 的分类变量

c++ - 对于以下类型的数据表示,什么是好的数据结构?