GNU 병렬 및 분할 사용

GNU 병렬 및 분할 사용

꽤 큰 파일을 postgresql 데이터베이스에 로드하고 있습니다. 이를 위해 먼저 split파일을 사용하여 더 작은 파일(각각 30Gb)을 얻은 다음 GNU Parallel각 더 작은 파일을 데이터베이스에 로드하는 데 사용했습니다 psql copy.

문제는 파일을 분할한 후 코어당 하나의 파일을 로드하기 시작하는 데 약 7시간이 걸린다는 것입니다. 나에게 필요한 것은 파일 쓰기가 끝날 때마다 파일 이름을 std 출력에 인쇄하여 쓰기가 끝나면 split파이프 Parallel하고 파일 로드를 시작할 수 있도록 하는 방법입니다 . split이 같은:

split -l 50000000 2011.psv carga/2011_ | parallel ./carga_postgres.sh {}

split매뉴얼 페이지를 읽었 지만 아무것도 찾을 수 없습니다. split다른 도구나 다른 도구를 사용하여 이를 수행할 수 있는 방법이 있습니까 ?

답변1

--pipeline을 사용하세요:

cat 2011.psv | parallel --pipe -l 50000000 ./carga_postgres.sh

파일이 아닌 표준 입력에서 읽으려면 ./carga_postgres.sh가 필요하며 GNU 병렬 버전 < 20130222에서는 속도가 느립니다.

정확히 50000000개의 행이 필요하지 않은 경우 --block이 더 빠릅니다.

cat 2011.psv | parallel --pipe --block 500M ./carga_postgres.sh

그러면 약 500MB의 분할 청크가\n 전달됩니다.

./carga_postgres.sh에 무엇이 포함되어 있는지는 모르지만 사용자 이름과 비밀번호가 포함된 psql이 포함되어 있는 것 같습니다. 이 경우 GNU SQL(GNU Parallel의 일부)을 사용할 수 있습니다.

cat 2011.psv | parallel --pipe --block 500M sql pg://user:pass@host/db

주요 이점은 임시 파일을 저장할 필요가 없지만 모든 파일을 메모리/파이프라인에 보관할 수 있다는 것입니다.

./carga_postgres.sh가 표준 입력에서 읽을 수 없지만 파일에서 읽어야 하는 경우 파일에 저장할 수 있습니다.

cat 2011.psv | parallel --pipe --block 500M "cat > {#}; ./carga_postgres.sh {#}"

대규모 일자리는 종종 중도에 놓이게 됩니다. GNU Parallel은 실패한 작업을 다시 실행하여 도움을 줄 수 있습니다.

cat 2011.psv | parallel --pipe --block 500M --joblog my_log --resume-failed "cat > {#}; ./carga_postgres.sh {#}"

실패하면 위 명령을 다시 실행할 수 있습니다. 성공적으로 처리된 블록은 건너뜁니다.

답변2

GNU Parallel에서 --pipe 및 --pipepart를 사용하지 않는 이유는 무엇입니까? 이렇게 하면 추가 cat이 제거되고 디스크에서 직접 파일을 읽기 시작합니다.

parallel --pipe --pipepart -a 2011.psv --block 500M ./carga_postgres.sh

답변3

여기에 게시된 답변이 매우 복잡하다는 것을 알았기 때문에 Stack Overflow에 문의하여 답변을 받았습니다.이것답변:

당신이 사용하는 경우GNU split, --filter옵션을 사용하여 이 작업을 수행 할 수 있습니다.

'--filter=command'
이 옵션을 사용하면 단순히 각 출력 파일에 쓰는 대신 지정된 쉘 명령이 파이프를 통해 각 출력 파일에 기록됩니다. 명령은 명령을 호출할 때마다 다른 출력 파일 이름으로 설정되는 $FILE 환경 변수를 사용해야 합니다.

파일을 생성하고 백그라운드에서 Cargo_postgres.sh를 시작하는 쉘 스크립트를 생성할 수 있습니다.

#! /bin/sh

cat >$FILE
./carga_postgres.sh $FILE &

이 스크립트를 필터로 사용하십시오.

split -l 50000000 --filter=./filter.sh 2011.psv

답변4

파일 이름을 인쇄하는 또 다른 방법은 split파일이 준비되는 시기를 감지하는 것입니다. Linux에서는 다음을 사용할 수 있습니다.inotify특히 시설inotifywait유용.

inotifywait -m -q -e close_write --format %f carga | parallel ./carga_postgres.sh &
split -l 50000000 2011.psv carga/2011_

수동으로 죽여야 합니다 inotifywait. 잠재적인 경쟁 조건으로 인해 자동으로 종료하는 것은 약간 어렵습니다. 완료되자마자 종료하면 split아직 보고되지 않은 이벤트를 수신했을 수 있습니다. 모든 이벤트가 보고되도록 하려면 일치하는 파일 수를 세십시오.

{
  sh -c 'echo $PPID' >inotifywait.pid
  exec inotifywait -m -q -e close_write --format %f carga
} | tee last.file \
  | parallel ./carga_postgres.sh &
split -l 50000000 2011.psv carga/2011_
(
  set carga/2011_??; eval "last_file=\${$#}"
  while ! grep -qxF "$last_file" last.file; do sleep 1; done
)
kill $(cat inotifywait.pid)

관련 정보