使用C++; 我的目标是在OSX环境下,在QT项目中用C++解析大型CSV文件。 (当我说csv时,我指的是tsv和其他1GB~5GB的变体)
这似乎是一项简单的任务,但当文件大小变大时,事情会变得复杂。我不想编写自己的解析器,因为有许多与解析csv文件相关的边缘情况 我已经找到了各种csv处理库来处理这项工作,但在我的机器上解析1GB文件大约需要90~120秒,这是不可接受的。我现在没有对数据做任何事情,我只是为了测试目的处理和丢弃数据 是我尝试过的图书馆之一。但唯一足够快的库是,它给出了可接受的结果:在我的机器上15秒,但它只有在已知文件结构时才能工作 示例使用:使用C++; 我的目标是在OSX环境下,在QT项目中用C++解析大型CSV文件。 (当我说csv时,我指的是tsv和其他1GB~5GB的变体),c++,qt,csv,large-files,C++,Qt,Csv,Large Files,这似乎是一项简单的任务,但当文件大小变大时,事情会变得复杂。我不想编写自己的解析器,因为有许多与解析csv文件相关的边缘情况 我已经找到了各种csv处理库来处理这项工作,但在我的机器上解析1GB文件大约需要90~120秒,这是不可接受的。我现在没有对数据做任何事情,我只是为了测试目的处理和丢弃数据 是我尝试过的图书馆之一。但唯一足够快的库是,它给出了可接受的结果:在我的机器上15秒,但它只有在已知文件结构时才能工作 示例使用: #包括“csv.h” int main(){ io::CSVRead
#包括“csv.h”
int main(){
io::CSVReader in(“ram.csv”);
在.read_标题中(io::忽略额外_列,“供应商”、“大小”、“速度”);
字符串供应商;整数大小;双速度;
while(在行中(供应商、尺寸、速度)){
//处理数据
}
}
正如您所看到的,我不能加载任意文件,我必须专门定义变量以匹配我的文件结构。我不知道有任何方法允许我在运行时动态创建这些变量
我尝试过的另一种方法是使用LineReader类逐行读取csv文件,这非常快(读取整个文件大约需要7秒),然后使用可以处理字符串的lib解析每一行,但这需要大约40秒,与第一次尝试相比,这是一种改进,但仍然无法接受
我见过各种与csv文件解析相关的堆栈溢出问题,其中没有一个需要考虑大文件处理
我还花了很多时间在谷歌上寻找这个问题的解决方案,我真的很怀念像npm或pip这样的包经理在搜索现成解决方案时所提供的自由
对于如何处理这个问题,我将不胜感激
编辑:
使用的方法时,处理时间减少到25秒,这是一个很大的改进
我们可以进一步优化它吗?我假设您只使用一个线程 多线程可以加快进程 到目前为止,最好的成绩是40秒。让我们坚持下去 我假设您先阅读,然后处理->(大约7秒读取整个文件) 7秒阅读 33秒用于处理 首先您可以将文件分成块,比如50MB。 这意味着您可以在读取50MB文件后开始处理。您不需要等到整个文件完成。 读取时间为0.35秒(现在处理时间为0.35+33秒=cca 34秒) 使用多线程时,可以一次处理多个块。从理论上讲,这可以加速这个过程,达到你们的核心数。假设你有4个核。 这是33/4=8.25秒 我认为您可以使用4个内核加快处理速度,总共9秒。 看和或 我更喜欢游泳池 将任务分为几个部分:
loopoverfile {
whenever chunk is ready {
ChunkProcessor *chunkprocessor = new ChunkProcessor(chunk);
QThreadPool::globalInstance()->start(chunkprocessor);
connect(chunkprocessor, SIGNAL(finished(std::shared_ptr<ProcessedData>)), this, SLOT(readingFinished(std::shared_ptr<ProcessedData>)));
}
}
或者你可以使用主要的想法:(我不知道为什么阅读需要7秒,它背后是什么)
QFile文件(“in.txt”);
如果(!file.open(QIODevice::ReadOnly | QIODevice::Text))
返回;
QByteArray*数据=新的QByteArray;
整数计数=0;
而(!file.atEnd()){
++计数;
数据->附加(file.readLine());
如果(计数>10000){
ChunkProcessor*ChunkProcessor=新的ChunkProcessor(数据);
QThreadPool::globalInstance()->启动(chunkprocessor);
连接(chunkprocessor,SIGNAL(finished(std::shared_ptr)),此,插槽(readingFinished(std::shared_ptr));
数据=新的QByteArray;
计数=0;
}
}
一个文件,一个线程,读取速度几乎和“无”中断地逐行读取一样快。
处理数据是另一个问题,但与I/O无关。它已经在内存中。
因此,唯一需要考虑的是机器上的5GB文件和RAM容量
这是一个非常简单的解决方案,所有您需要的是子类QRunnable、重新实现run函数、完成时发出信号、使用共享指针传递处理后的数据,并在主线程中将该数据连接到一个结构或其他任何结构中。简单的线程安全解决方案。我会提出一个多线程的建议,但有一点不同,即一个线程专用于读取预定义(可配置)大小的数据块,并不断将数据提供给一组线程(基于多个cpu核)。假设配置如下所示: 块大小=50MB
磁盘线程=1
进程线程数=5
loopoverfile {
whenever chunk is ready {
ChunkProcessor *chunkprocessor = new ChunkProcessor(chunk);
QThreadPool::globalInstance()->start(chunkprocessor);
connect(chunkprocessor, SIGNAL(finished(std::shared_ptr<ProcessedData>)), this, SLOT(readingFinished(std::shared_ptr<ProcessedData>)));
}
}
qRegisterMetaType<std::shared_ptr<ProcessedData>>("std::shared_ptr<ProcessedData>");
QByteArray data = file.readAll();
QFile file("in.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QByteArray* data = new QByteArray;
int count = 0;
while (!file.atEnd()) {
++count;
data->append(file.readLine());
if ( count > 10000 ) {
ChunkProcessor *chunkprocessor = new ChunkProcessor(data);
QThreadPool::globalInstance()->start(chunkprocessor);
connect(chunkprocessor, SIGNAL(finished(std::shared_ptr<ProcessedData>)), this, SLOT(readingFinished(std::shared_ptr<ProcessedData>)));
data = new QByteArray;
count = 0;
}
}