我有一个很大的csv文件(25 mb)代表一个对称图(大约18kX18k).在将其解析为向量数组时,我已经分析了代码(使用VS2012 ANALYZER)并且它显示了在读取每个字符(getline :: basic_string :: operator + =)时发生解析效率(总共大约19秒)的问题如下图所示:
这让我感到沮丧,因为使用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);
Run Code Online (Sandbox Code Playgroud)
init第一行和最后一行基本上与上面的循环做同样的事情,但initFirstRow也计算列数.
VertexSet基本上是索引(int)的向量.每个顶点读取(由','分隔)长度不超过7个字符长(值介于-1和1之间).
在25兆字节,我猜你的文件是机器生成的.因此,您(可能)不需要担心诸如验证格式之类的事情(例如,每个逗号都已到位).
鉴于文件的形状(即每行很长),您可能不会通过将每行放入a stringstream来解析数字来施加大量开销.
基于这两个事实,我至少考虑编写一个将逗号视为空格的ctype方面,然后使用该方面使用区域设置填充字符串流,以便轻松解析数字.整体代码长度会更大一些,但代码的每个部分最终都会非常简单:
#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";
}
Run Code Online (Sandbox Code Playgroud)
为了测试这个,我生成了一个伪随机双打的1.8K x 1.8K 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";
}
}
Run Code Online (Sandbox Code Playgroud)
这产生了大约27兆字节的文件.在使用gcc(g++ -O2 trash9.cpp)编译读取/解析代码后,我的笔记本电脑上的快速测试显示它在大约0.18到0.19秒内运行.它似乎永远不会使用(甚至接近)所有的一个CPU核心,表明它是I/O绑定的,所以在桌面/服务器机器上(具有更快的硬盘驱动器)我希望它仍然运行得更快.