2017-01-17 4 views
4

목표GNU 병렬 : 어린이

사용 GNU 병렬로 분할 파일은 어린이에 큰 된 .gz 파일을 분할합니다. 서버에는 16 개의 CPU가 있으므로 16 개의 자식을 만듭니다. 각 어린이는 많아야 N 줄을 포함해야합니다. 여기서, N = 104,214,420 라인. 아이들은 .gz 형식이어야합니다.

입력 파일

  • 이름 : file1.fastq.gz
  • 크기 : 39기가바이트
  • 라인 수 : 1,667,430,708 (비 압축)

하드웨어

  • 36기가바이트 메모리
  • 16 개의 CPU
  • HPCC 환경 (내가 관리하지 않다)

코드

버전 1

zcat "${input_file}" | parallel --pipe -N 104214420 --joblog split_log.txt --resume-failed "gzip > ${input_file}_child_{#}.gz" 

3 일 후 그 일은 끝나지 않았다. split_log.txt가 비어 있습니다. 출력 디렉토리에는 자식이 없습니다. 로그 파일은 Parallel이 --block-size을 1MB (기본값)에서 2GB 이상으로 증가 시켰음을 나타냅니다. 이 버전 2

# --block-size 3000000000 means a single record could be 3 GB long. Parallel will increase this value if needed. 

zcat "${input_file}" | "${parallel}" --pipe -N 104214420 --block-size 3000000000 --joblog split_log.txt --resume-failed "gzip > ${input_file}_child_{#}.gz" 

작업이 ~ 2 시간 동안 실행 된

버전 2에 코드를 변경 나에게 영감을. split_log.txt가 비어 있습니다. 아직 출력 디렉토리에 자식이 표시되지 않습니다.

parallel: Warning: --blocksize >= 2G causes problems. Using 2G-1. 

질문

  1. 내 코드를 향상시킬 수있는 방법 : 지금까지 파일은 다음과 같은 경고를 보여 로그?
  2. 이 목표를 달성하는 더 빠른 방법이 있습니까?
+0

입력 파일을 잘 모르겠습니다. 16 개의 CPU를 가지고 있기 때문에 파일 당 1 억 4 백만 라인이 필요하다면 입력 파일에 16 억 개의 라인이 있다고 추론합니다. 그런 다음 레코드가 각각 3GB라고 가정하면 3GB의 16 억 레코드가 39GB 파일로 압축됩니다. 나는 압축 알고리즘을 원한다고 생각하고있다 :-) 내가 잘못 이해 한 부분을 조언 해주기 바란다. –

+0

@MarkSetchell : file1.fastq.gz (39GB)에는 1,667,430,708 행이 포함되어 있습니다. 자녀는 많아야 각각 104,214,420 줄을 포함해야합니다. 솔직히, 나는 가장 큰 라인/레코드의 크기를 모른다. 나는 --block-size 3000000000에 Parallel이 크기를 1MB (기본값)에서 2GB 이상으로 늘렸다는 사실을 알게되었다. 나는 3GB가 안전하다고 생각했다. 제발 깨달으십시오 :) –

+0

죄송합니다, 계몽 할 수 없습니다 - 나는 깨닫지 못합니다 :-(이해하려고 노력하고 있습니다. 우리가 올레가 우리 모두에게 계몽을 기다려야한다고 생각합니다 :-) –

답변

2

파일이 fastq 파일이고 따라서 레코드 크기가 4 라인이라고 가정합시다.

GNU Parallel에 -L 4으로 알려주십시오.

fastq 파일에서 순서는 중요하지 않으므로 n * 4 줄의 블록을 하위 항목으로 전달하려고합니다.

그 효율적으로 압축 파일을 작동하지 않습니다 --pipe-part 제외 --pipe-part를 사용하고 -L 작동하지 않습니다 이렇게하려면, 그래서 당신은 --pipe에 만족해야한다.
zcat file1.fastq.gz | parallel -j16 --pipe -L 4 --joblog split_log.txt --resume-failed "gzip > ${input_file}_child_{#}.gz" 

16 개 어린이 및 기록 경계 (즉, 4 개 라인)에서 잘게 1 MB, 행 블록 기본값 블록을 전달한다. 각 블록에 대해 작업을 실행합니다. 하지만 실제로 원하는 것은 총 16 개의 작업으로만 입력을 전달하는 것입니다. 그러면 해당 라운드 로빈을 수행 할 수 있습니다. 불행하게도 --round-robin의 임의성의 요소는, 그래서 --resume-failed이 작동하지 않습니다 :

zcat file1.fastq.gz | parallel -j16 --pipe -L 4 --joblog split_log.txt --round-robin "gzip > ${input_file}_child_{#}.gz" 

parallel가 16 GZip으로 압축하여 계속 고군분투 될 것입니다,하지만 당신은 100~200메가바이트/S를 압축 할 수 있어야한다.

지금 경우 당신은 우리가 더 빨리 그것을 할 수있는 미 압축 fastq 파일을했지만, 우리는 약간의 속임수해야합니다 :

@EAS54_6_R1_2_1_413_324 
CCCTTCTTGTCTTCAGCGTTTCTCC 
+ 
;;3;;;;;;;;;;;;7;;;;;;;88 
@EAS54_6_R1_2_1_540_792 
TTGGCAGGCCAAGGCCGATGGATCA 
+ 
;;;;;;;;;;;7;;;;;-;;;3;83 
@EAS54_6_R1_2_1_443_348 
GTTGCTTCTGGCGTGGGTGGGGGGG 
+EAS54_6_R1_2_1_443_348 
;;;;;;;;;;;9;7;;.7;393333 
: 종종 fastq 파일에서 동일한 문자열을 시작하는 sqlName를있을 것이다

여기에 @EAS54_6_R입니다. 아쉽게도 이것은 품질 회선의 유효한 문자열입니다 (은 실제로). 실제로는 @EAS54_6_R으로 시작하는 품질 회선을 보는 데 매우 놀랐습니다. 그것은 단지 일어나지 않습니다.

\n 다음에 @EAS54_6_R을 레코드 구분 기호로 사용할 수 있으므로 --pipe-part을 사용할 수 있으므로 이점을 활용할 수 있습니다. 추가 혜택은 주문이 동일하게 유지된다는 것입니다. 여기 file1-fastq의 크기의 1/16에 블록 크기를 제공 할 것입니다 :

parallel -a file1.fastq --block <<1/16th of the size of file1.fastq>> -j16 --pipe-part --recend '\n' --recstart '@EAS54_6_R' --joblog split_log.txt "gzip > ${input_file}_child_{#}.gz" 

을 당신이 당신을 위해 계산을 할 수있는 GNU 병렬 20161222 다음 GNU 병렬를 사용하는 경우. --block -1 의미 : 블록 크기를 선택하여 16 개의 작업 슬롯 각각에 하나의 블록을 제공 할 수 있습니다.

parallel -a file1.fastq --block -1 -j16 --pipe-part --recend '\n' --recstart '@EAS54_6_R' --joblog split_log.txt "gzip > ${input_file}_child_{#}.gz" 

여기 GNU Parallel은 20 GB/s를 쉽게 전송할 수 있습니다.

그것은 recstart 값이되어야 하는지를 확인하기 위해 파일을 열 필요 성가신, 그래서 이것은 대부분의 경우에 작동합니다 : 여기

parallel -a file1.fastq --pipe-part --block -1 -j16 
--regexp --recend '\n' --recstart '@.*\n[A-Za-z\n\.~]' 
my_command 

우리는 선이 다음과 같이 시작한다고 가정

@ 
[A-Za-z\n\.~] 
anything 
anything 

'@'로 시작하는 몇 줄의 품질 줄이있는 경우에도 품질 줄에 항상 [A-Za-z \ n. ~]로 시작하는 줄이 따라 오지 않습니다. seqname 행은 @로 시작합니다.


당신은 또한 압축되지 않은 파일의 1/16에 해당 너무 큰 블록 크기를 가질 수 있지만, 나쁜 생각 될 것이다 :

  • 당신은 유지할 수있을 것 RAM의 전체 압축되지 않은 파일
  • 마지막 gzip은 마지막 바이트를 읽은 후에 만 ​​시작됩니다. (첫 번째 gzip은 아마도 그 때까지 수행됩니다).104,214,420에 레코드의 수를 설정하여

은 (-N 사용) 당신이 무엇을하고 있는지 기본적으로, 당신의 서버는 아마 RAM의 그것 36기가바이트에 압축되지 않은 데이터의 150 GB의 유지에 어려움을 겪고있다.

+0

당신은 학자이고 현명한 사람입니다. 고맙습니다! 질문 : FASTQ 파일을 쌍으로 처리한다고 가정 해 봅시다. 예를 들어, paired-end sequencing (생물 정보학 용어)에서는 file1.r1.fastq.gz와 file1.r2.fastq.gz라는 두 개의 FASTQ 파일이 있습니다. 여기서는 순서가 중요합니다. r1 파일의 레코드 1은 r2 파일의 레코드 1과 쌍을 이루는 방식으로, 나중에 분석에 사용됩니다. 이 시나리오에 맞게 병렬 명령이 어떻게 생겼을까요? –

0

페어런트 엔드는 제한이 있습니다. 순서는 중요하지 않지만 순서는 다른 파일에 대해 예측 가능해야합니다. 예 : file1.r1.fastq.gz의 n 레코드는 file1.r2.fastq.gz의 레코드 n과 일치해야합니다.

split -n r/16은 간단한 라운드 로빈을 수행하는 데 매우 효율적입니다. 그러나 다중 행 레코드를 지원하지는 않습니다. 그래서 우리는 4 번째 줄마다 레코드 분리 자로 \ 0을 삽입합니다. 분할 후 제거됩니다. --filter 입력에 명령을 실행, 그래서 우리는 비 압축 데이터를 저장할 필요가 없습니다

doit() { perl -pe 's/\0//' | gzip > $FILE.gz; } 
export -f doit 
zcat big.gz | perl -pe '($.-1)%4 or print "\0"' | split -t '\0' -n r/16 --filter doit - big. 
파일 이름이 big.aa.gz 지정됩니다

.. big.ap.gz합니다.

+0

고마워, 또! 나는 지금 이것을 읽고있다. 어제 저는 놀고 있었고 제가 보여 드리고 싶은 코드를 생각해 냈습니다 : parallel zcat {} '|' split -l $ {child_num_lines} --filter = \ ''gzip> $ FILE.gz '\'- $ {temp_dir}/{} _ ::: "$ {r1_fastq_gz}" "$ {r2_fastq_gz}" 귀하의 코드와 동일하지만 예측 가능한 순서를 유지하면서 다른, 그리고 가능성이 천천히, 방식으로? –