2016-09-20 3 views
0

저는 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

전체 파일을 한 번에 읽는 대신 작은 덩어리로 읽으십시오. http://stackoverflow.com/questions/20911584/how-to-read-a-file-in-multiple-chunks-until-eof-c – Oscar

+0

'content + = line; '물론 느립니다. 메모리를 재 할당하고, 내용을 복사하고, 새 행을 추가하는 데는 시간이 걸립니다. 오스카 (Oscar)는 그런 접근 방식을 다시 생각해 볼 수도 있습니다. –

+1

'out << id << ":"<< len << endl;'endl'은 줄 바꿈 만하는 것이 아닙니다. 또한 버퍼를 플러시합니다. 필요하지 않은 경우에는 사용하지 마십시오. 그냥'\ n'을 사용하십시오. – Matt

답변

1

왜 천천히입니까?

fasta 파일이 상당히 클 수 있습니다. 그러나 그것은 C++에서 결코 문제가되지 않습니다. 가장 좋은 방법은 프로파일 러를 사용하는 것입니다.

그러나 여기에서 문자열 할당은 매우 좋은 후보 근본 원인입니다. 문자열의 끝에 읽은 모든 줄이 추가되어 문자열이 커집니다. 이것은 content의 성장으로 인해 자주 재 할당된다는 의미입니다. 할당 증가, 복사, 메모리 할당 해제 등이 필요한만큼 많이 발생합니다!

이러한 접근 방식은 힙 조각화를 유발할 수 있으며 수십만 번 수행하면 프로세스 속도가 상당히 느려질 수 있습니다. 다행히도이를 더 빠르게 수행 할 수있는 몇 가지 전략이 있습니다.

쉽게 속도를 내려면 어떻게해야합니까?

reserve()을 사용하여 content에 충분한 공간을 사전 할당 할 수 있습니다. 이것은 쉽게 가속기가 될 수 있습니다. 특히 뉴 클레오 티드의 평균 크기를 알고있는 경우에 그러합니다. 그러나 그렇지 않더라도 재 할당 노력을 많이 줄일 수 있습니다.

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

어떻게 그것을 더 속도를 :

다만 차이가 있는지 관찰이 시도?

매우 효과적 일뿐만 아니라 seekg()tellg()와 FASTA 파일의 크기를 결정하는 것입니다 수있는 또 다른 방법은, 다음 fread()와 하나의 읽기에 메모리에 파일을로드 및 구문 분석/처리 직접적 어디를 읽었 어.

매우 원시 처리 방식을 사용하면 Gb/s 범위의 처리량을 확보해야합니다.

마지막으로 중요한 것은 성능 측정을 위해 릴리스 모드 (최적화 프로그램 사용)에서 C++ 코드를 컴파일하는 것을 잊지 마십시오..

+0

답변 및 의견을 보내 주셔서 감사합니다. 많은 도움을 받았습니다. –

+0

@tov_Kirov 당신을 환영합니다! 호기심에서 : 마침내 무엇을 했습니까? 그리고 지금 당신이 관찰하는 속도는 무엇입니까? – Christophe

2

어쩌면 전체 파일이나 블록을 미리 할당 된 문자열로 읽어야합니다. 그런 다음 std::stringstream을 사용하여 필요에 따라 파일을 처리하십시오. 다음은 프로그램에서 사용하는 예제입니다. 내 파일은 크기가 크지 않지만 각 파일의 수천 줄이 포함되어 있으며 각 파일은 특정 문자, 복사 된 파일 등으로 파싱됩니다. 그리고이 파일은 몇 밀리 초 (가장 큰 파일의 경우 약 50ms,로드 및 파싱) 만 소요됩니다.당신이 할 수

//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 파일을 읽을 수있는 공간이 충분하지 않은 경우 chuncks을 읽고이 적응

...

하나 더 최적화. @Adrian이 말했듯이 content += line은 꽤 느립니다 ... 코드를 보면 시작 및 중지 인덱스를 저장하면서 데이터를 복사하지 않고 '>' 문자를 찾고 싶을 수 있습니다. 그런 다음 메모리를 한 번만 할당하고 발견 된 시작 및 중지 인덱스를 사용하여 데이터를 복사합니다 (또는 시작 및 중지 인덱스의 데이터 구조를 작성하십시오 :-)). 그것이 내 파일을 구문 분석하는 데 사용됩니다. 나는 std::stringfind_first_of, find_first_not_of, find_last_ofsubstr 방법을 사용합니다. 이것들은 아마도 차선책 일 뿐이지 만 코드를 읽을 수 있고 내 목적을 위해 충분히 빠릅니다.

내 답변을 통해 무엇을 할 것인지 힌트를 얻고 프로그램 속도를 높일 수 있기를 바랍니다.

또한 프로필러를 사용하여 무엇이 가장 많은 시간을 차지하는지 파악하는 것이 좋습니다. 예를 들어, Visual Studio 2015의 네이티브입니다. 당신은 out << ... << endl을 사용하고

안부

1

. 그것은 한 줄을 디스크에 직접 플러시합니다. 디스크는 문자 지향적이지 않으므로 읽기 - 수정 - 쓰기 작업을 의미합니다.

대신 out << '\n'을 사용하여 을 입력하면 새 줄이 개입니다. 디스크 캐시가이를 처리합니다.