fasta — C ++ для чтения / записи больших файлов

Я очень новичок в C ++! Поэтому я был бы очень признателен, если бы вы рассмотрели это и ответили как можно проще. Мне нужно разобрать файл fasta с> 40000 последовательностями (около 500 Мб) и записать 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

Решение

Возможно, вам следует прочитать весь файл или его блок в заранее выделенную строку. А затем использовать 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 довольно медленно … глядя на ваш код, вы можете искать '>' символ при сохранении индексов запуска и остановки, при этом не копируя данные. После этого вы только один раз выделите память и скопируете данные, используя найденные индексы start и stop (или просто создайте структуру данных индексов start и stop :-)). Это то, что я использую для анализа моих файлов. Я использую std::string«s find_first_of, find_first_not_of, find_last_of а также substr методы. Хотя они, вероятно, неоптимальны, они сохраняют код читабельным и достаточно быстрыми для моей цели.

Я надеюсь, что мой ответ даст вам подсказку о том, что делать, и что он поможет вам ускорить вашу программу.

Кроме того, это хорошая идея использовать профилировщик, чтобы определить, что занимает у вас больше всего времени. Например, на Visual Studio 2015.

С наилучшими пожеланиями

2

Другие решения

Вы используете out << ... << endl, Это сбрасывает одну строку прямо на диск. Поскольку диски не являются символьно-ориентированными, это означает операцию чтения-изменения-записи.

Вместо этого используйте out << '\n' написать просто новая строка. Дисковый кеш справится с этим.

1

Почему это медленно?

FASTA файл может быть довольно большим. Но это ни в коем случае не проблема в C ++.
Лучший способ узнать это — использовать профилировщик.

Но здесь распределение строк — очень хорошая причина-кандидат: каждая прочитанная строка добавляется в конец строки, вызывая рост строки. Это означает частое перераспределение из-за contentРост, который вызывает выделение, копирование, освобождение памяти и многое другое!

Такой подход может привести к фрагментации кучи и значительно замедлить процесс, если это будет сделано несколько сотен тысяч раз. К счастью, есть несколько стратегий сделать это быстрее.

Как быстро это ускорить?

Ты можешь использовать reserve() предварительно выделить достаточно места для content, Это может быть легким ускорителем, особенно если вы знаете средний размер вашего нуклеотида. Но даже если вы этого не сделаете, это может сократить объем перераспределительных усилий.

Просто попробуйте это, чтобы увидеть, если есть разница:

    content.reserve (100000);   // just before entering into the loop.

Как ускорить это дальше?

Другой подход, который также может быть очень эффективным, — это определить размер вашего файла fasta с помощью seekg() а также tellg(), а затем загрузить файл в память в одно чтение с fread()и проанализировать / обработать его непосредственно там, где вы его прочитали.

С этим очень грубым подходом вы должны получить пропускную способность в диапазоне Гбит / с.

Последний, но тем не менее важный, не забудьте скомпилировать код C ++ в режиме релиза (оптимизатор включен) для измерения производительности.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector