0

下面给出了我当前的解析器 - 将 ~10MB CSV 读取到 STL 向量需要 ~30 秒,这对我来说太慢了,因为我有超过 100MB 需要在每次运行程序时读取。任何人都可以就如何提高性能提供一些建议吗?确实,在纯 C 语言中会更快吗?

int main() {
    std::vector<double> data;
    std::ifstream infile( "data.csv" );
    infile >> data;
    std::cin.get();
    return 0;
}

std::istream& operator >> (std::istream& ins, std::vector<double>& data)
{
    data.clear();

    // Reserve data vector
    std::string line, field;
    std::getline(ins, line);
    std::stringstream ssl(line), ssf;

    std::size_t rows = 1, cols = 0;
    while (std::getline(ssl, field, ',')) cols++;
    while (std::getline(ins, line)) rows++;

    std::cout << rows << " x " << cols << "\n";

    ins.clear(); // clear bad state after eof
    ins.seekg(0);

    data.reserve(rows*cols);

    // Populate data
    double f = 0.0;
    while (std::getline(ins, line)) {
        ssl.str(line);
        ssl.clear();
        while (std::getline(ssl, field, ',')) {
            ssf.str(field);
            ssf.clear();
            ssf >> f;
            data.push_back(f);
        }
    }
    return ins;
}

注意:我还可以使用 openMP,其内容最终将用于 CUDA 的 GPGPU 计算。

4

4 回答 4

5

您可以通过一次而不是两次读取文件来节省一半的时间。

虽然调整向量的大小是有益的,但它永远不会主导运行时,因为 I/O 总是会慢一些。

另一种可能的优化可能是在没有字符串流的情况下读取。类似的东西(未经测试)

int c = 0;
while (ins >> f) {
    data.push_back(f);
    if (++c < cols) {
        char comma;
        ins >> comma; // skip comma
    } else {
        c = 0; // end of line, start next line
    }
}

如果您可以省略,并仅用空格分隔值,则它甚至可能是

while (ins >> f)
    data.push_back(f);

或者

std::copy(std::istream_iterator<double>(ins), std::istream_iterator<double>(),
          std::back_inserter(data));
于 2013-04-29T22:13:27.920 回答
3

在我的机器上,您的保留代码大约需要 1.1 秒,而您的填充代码需要 8.5 秒。

添加 std::ios::sync_with_stdio(false); 对我的编译器没有任何影响。

下面的 C 代码需要 2.3 秒。

int i = 0;
int j = 0;
while( true ) {
    float x;
    j = fscanf( file, "%f", & x );
    if( j == EOF ) break;
    data[i++] = x;
    // skip ',' or '\n'
    int ch = getc(file);
}
于 2013-04-29T23:08:59.710 回答
2

试着打电话

std::ios::sync_with_stdio(false);

在您的程序开始时。cin这会禁用/coutscanf/之间的(据称非常慢)同步printf(我自己从未尝试过,但经常看到推荐,例如这里)。请注意,如果这样做,则不能在程序中混合使用 C++ 风格和 C 风格的 IO。

(此外,Olaf Dietsche 只读取文件一次是完全正确的。)

于 2013-04-29T22:24:57.523 回答
-1

显然,文件 io 是个坏主意,只需将整个文件映射到内存中,将 csv 文件作为连续的 vm 块访问,这只会产生一些系统调用

于 2013-04-30T05:07:24.683 回答