2016년 11월 23일 수요일

GNU Parallel

대량의 파일에 대한 반복 작업을 어떻게 하여 효율적으로 진행할 수 있을까? HPC cluster니 하둡이니 클라우드 컴퓨팅이니 하는 기술적으로 다소 까다로운 방법 말고 좀 더 간단한 방법은 없을까? 이러한 고민 끝에 발견한 것이 바로 GNU Parallel이다(공식 웹사이트). 이것은 간단히 말하자면 입력을 쪼개서 병렬 실행을 해 주는 shell 수준의 도구이다. 다중 코어를 지닌 한 대의 컴퓨터는 물론, ssh로 접속 가능한 여러 컴퓨터에 작업을 보내는 것도 가능하다. 반복 작업을 위한 기존의 유틸리티인 xargs 또는 cat | bash를 대체할 수 있다는 뜻이다.

만약 현 디렉토리에 있는 수천개 이상의 파일을 전부 압축해야 한다고 가정하자. gzip *이라고 타이프하면 십중팔구는 인수가 너무 많아서 실행을 하지 못한다는 에러 메시지가 나올 것이다. 그러나 Parallel이 설치되었다면 다음과 같이 하면 된다.
$ parallel gzip ::: *
Shell은 *를 확장하여 파일로 만들고, 이를 gzip 명령어에 공급하되 여러 core에서 병렬 작업이 일어나게 한다. 물론 이는 대단히 간단한 사례이다. 입력 파일을 분할하여(기본 가정은 ㄱ각각의 라인이 별도의 레코드라는 것이나, separator를 지정할 수 있다) 각각에 대한 동시 작업을 수행하고, 이를 합치는 것이 가장 전형적인 사례이다. 분할된 입력 파일은 명령어에게 표준 입력으로 전송되게 함으로써 매우 단순한 작업 지시를 할 수 있다. Biostars에 매우 훌륭한 설명 자료가 있다(Parallelize serial command line programs without changing them). 이 자료에서 설명한 사례를 하나 인용해 보겠다. 1GB나 되는 대용량의 fasta file에 대한 blast 검색을 하고 싶다면?
$ cat 1gb.fasta | parallel --block 100k --recstart '>' --pipe blastp -evalue 0.01 -outfmt 6 -db db.fa -query - > results
입력 파일을 100 KB 단위로 자르되 각 레코드는 '>'로 시작하니 미련하게 query sequence 중간을 자르지 못하게 하고, 이를 blastp에 넘겨서 서열 검색을 한 뒤 최종적으로는 results 파일로 합친다. 잘려진 각 데이터에 대한 검색 결과까지 순서대로 저장되는 것은 아니니, 입력물의 순서를 그대로 유지해야 한다면 약간의 변형된 방법이 필요하다.

다음으로는 FASTX toolkit에 들어있는 fastq_to_fastq(-Q33)을 그냥 실행한 것과 GNU parallel을 거쳐서 실행한 것의 소요시간 차이를 비교해 보았다. 중간에 top을 쳐 보면 12개의 job이 동시에 돌아간 것으로 나온다. 블록 사이즈나 jop 수는 따로 지정하지 않았다. 먼저 그냥 실행한 것. 입력한 fastq 파일의 크기는 5.3 GB였다.

real 3m19.405s
user 3m14.986s
sys 0m8.562s

다음은 GNU paralleld을 사용한 것. 상당한 속도 개선이 있다.

real 1m6.266s
user 5m40.297s
sys 1m22.576s

예전에는 fastq 파일을 처리하는 유틸리티를 실행하면서 종료되기는 그저 기다리고만 있었는데, 이제는 그럴 필요가 없겠다. 추가적으로 GNU Parallel을 remote host에 적용하는 방법을 익힌다면 최근에 확보한 중간급의 서버 10대 정도를 묶어서 활용하는데 매우 큰 도움이 될 것이다.

유용한 자료 링크를 몇가지 더 소개한다.

댓글 없음: