我是C ++的新手!因此,如果您能够考虑并尽可能轻松地回答我,我将非常感激。我需要使用> 40000序列(接近500Mb)解析fasta文件,并将ID和序列长度写入新文件。我发现在C ++中它的运行速度非常慢,为此目的,python工作得更快。但我需要学习如何在C ++中实现它。我很奇怪有没有办法为C ++加快这个过程?
这是我的代码:
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include <stdio.h>
using namespace std;
int main() {
time_t start, end;
time(&start);
clock_t begin = clock();
ifstream file;
string line;
string id;
string content;
int len = 0;
int i = 0;
ofstream out;
file.open("contigs.fasta", ios::in);
out.open("output.txt", ios::out);
while (getline(file, line)) {
if (line[0] == '>') {
i++;
if (i != 1) {
//cout << id << "\n" << len << "\n" << content << endl;
//out.write(line.c_str(), line.size());
out << id << " : " << len << endl;
}
id = line;
len = 0;
content = "";
}
else
{
len += line.length();
content += line;
}
}
//cout << id << "\n" << len << "\n" << content << endl;
//out << id << " : " << len << endl;
cout << "Total number of sequences :" << i << "\n";
out.close();
time (&end);
double dif = difftime (end,start);
printf ("Elasped time is %.2lf seconds.", dif );
return 0;
}
提前致谢!
答案 0 :(得分:2)
也许您应该将整个文件或其中的块读入预先分配的字符串中。然后使用std::stringstream
根据需要处理文件:以下是我在程序中使用的示例。我的文件不是那么大,但是它们包含数千行,然后每个行都会针对特定字符进行解析,复制等等。这只需要几毫秒(大文件大约50毫秒,加载和解析)。
//1- read the file
std::string str; // allocate string
{
//compute file size
int iFileSize = 0;
{
std::ifstream ifstr(rkFilename.c_str(), std::ios::binary); // create the file stream - this is scoped for destruction
if(!ifstr.good())
{
return;
}
//get the file size
iFileSize = ifstr.tellg();
ifstr.seekg( 0, std::ios::end ); // open file at the end to get the size
iFileSize = (I32) ifstr.tellg() - iFileSize;
}
//reopen the file for reading this time
std::ifstream ifstr(rkFilename.c_str());
//create a char* with right size
char* pcFileBuffer = new char[iFileSize];
//copy the full file in there
ifstr.read(pcFileBuffer, iFileSize);
//put it all into a string - could be optimised I guess
str = std::string(pcFileBuffer);
//bookeeping
delete[] pcFileBuffer;
pcFileBuffer = NULL;
}
// create a stream using the allocated string
// this stream works as a file reader basically so you can extract lines into string, etc...
std::stringstream filebuf(str);
//the rest is up to you
如果没有足够的空间将完整的500Mb文件读入内存,请将其修改为读取块...
您可以做的另一项优化。正如@Adrian所说,content += line
非常慢......查看代码时,您可能希望在保存启动和停止索引的同时查找'>'
字符,而不是复制数据。然后,您只需分配一次内存并使用找到的开始和停止索引复制数据(或者只是构建启动和停止索引的数据结构:-))。这就是我用来解析我的文件。我使用std::string
的{{1}},find_first_of
,find_first_not_of
和find_last_of
方法。虽然这些可能不是最理想的,但它们使代码可读并且足够快以达到我的目的。
我希望我的回答可以暗示你该做什么,并且它可以帮助你加快你的计划。
此外,最好使用分析器来确定最耗费时间的内容。例如,它在Visual Studio 2015上是原生的。
祝你好运
答案 1 :(得分:1)
为什么会慢?
fasta文件可能非常大。但这在C ++中绝不是问题。 最好的方法是使用分析器。
但是在这里,字符串分配是一个非常好的候选根本原因:每个行读取都添加在字符串的末尾,导致字符串增长。这意味着由于content
的增长而频繁重新分配,这会导致分配,复制,释放内存,并且远远超出需要!
此类方法可能会导致堆碎片,并且如果完成数十万次,则会大大减慢进程。幸运的是,有几种策略可以更快地完成此任务。
如何轻松加快速度?
您可以使用reserve()
为content
预分配空间。这可能是一个简单的加速器,特别是如果您知道核苷酸的平均大小。但即使你不这样做,它也可以减少很多重新分配工作。
试试看这是否存在差异:
content.reserve (100000); // just before entering into the loop.
如何进一步加快速度?
另一种非常有效的方法是使用seekg()
和tellg()
确定fasta文件的大小,然后使用{{1}在单个读取中将文件加载到内存中},并在您阅读它的地方直接解析/处理它。
使用这种非常原始的方法,您应该获得Gb / s范围内的吞吐量。
最后但同样重要的是,不要忘记在发布模式(优化程序开启)中编译C ++代码以进行性能测量。
答案 2 :(得分:1)
您正在使用out << ... << endl
。将单行直接刷新到磁盘。由于磁盘不是面向字符的,因此它意味着读 - 修改 - 写操作。
相反,使用out << '\n'
编写只是换行符。磁盘缓存将处理此问题。