병렬로 생성된 세 개의 다른 스트림에서 단일 출력 스트림 만들기

병렬로 생성된 세 개의 다른 스트림에서 단일 출력 스트림 만들기

세 가지 형식의 데이터가 있습니다. 각 데이터 유형마다 이를 단일 통합 형식으로 변환하는 Python 스크립트가 있습니다.

이 Python 스크립트는 느리고 CPU에 바인딩되어 있으므로(멀티 코어 시스템의 단일 코어에 대해) 세 개의 인스턴스(각 데이터 유형당 하나씩)를 실행하고 출력을 결합하여 sort. 이는 다음과 같습니다:

{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n

그러나 세 개의 스크립트는 병렬로 실행됩니다.

내가 찾은이 문제여기서 GNU는 split스트림을 처리하는 스크립트의 n 인스턴스 사이에서 표준 출력 스트림을 반복하는 데 사용됩니다.

분할 매뉴얼 페이지에서:

-n, --number=CHUNKS
          generate CHUNKS output files.  See below
CHUNKS  may be:
 N       split into N files based on size of input
 K/N     output Kth of N to stdout
 l/N     split into N files without splitting lines
 l/K/N   output Kth of N to stdout without splitting lines
 r/N     like 'l'  but  use  round  robin  distributio

따라서 r/N명령은 "구분선 없음".

이를 바탕으로 다음과 같은 해결 방법이 가능할 것으로 보입니다.

split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF

여기서이 곳은 choose_script:

#!/bin/bash
{ read x; ./handle_$x.py; }

불행하게도, 거기에 있으면 안 되는 많은 개행 문자뿐만 아니라 일부 줄이 섞여 있는 것을 볼 수 있습니다.

예를 들어, Python 스크립트를 다음을 수행하는 몇 가지 간단한 bash 스크립트로 바꾸는 경우:

#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;

.

#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;

.

#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;

다음 출력이 표시됩니다.

1-8394

2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981

이것은 짜증나는 일입니다. 위에 붙여넣은 매뉴얼 페이지에 따르면 라인 무결성을 유지해야 합니다.

분명히 매개변수를 제거하면 -u작동하지만 버퍼링이 발생하고 스크립트 중 하나를 제외한 모든 출력을 버퍼링하기 때문에 메모리가 부족해집니다.

누구든지 여기에 통찰력이 있다면 크게 감사하겠습니다. 나는 깊이를 벗어났습니다.

답변1

GNU 병렬 처리의 -u 옵션을 사용해 보십시오.

echo "1\n2\n3" | parallel -u -IX ./handle_X.sh

이는 전체 프로세스를 버퍼링하지 않고 병렬로 실행합니다.

답변2

노력하다:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py

파일 이름을 사용하는 경우 handle_1.py:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

출력이 혼합되는 것을 원하지 않으므로 -u를 사용하지 마십시오.

순서를 유지하려는 경우(따라서 모든 handler_1 출력이 handler_2 앞에 나오므로 정렬을 피할 수 있습니다):

parallel -k  ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

그래도 정렬하려면 병렬로 정렬하고 다음을 활용할 수 있습니다 sort -m.

parallel --files "./handle_{1}.py {2} | sort -n"  ::: 1 2 3 ::: files* | parallel -j1 -X sort -m

$TMPDIR을 출력을 저장할 만큼 큰 디렉터리로 설정합니다.

답변3

내가 뭔가를 놓친 것일 수도 있지만 이렇게 할 수는 없습니다.

(./handle_1.py & ./handle_2.py & ./handle_3.py) | sort -n

각 프로세스 내의 행이 인터리브되지 않도록 하려면 프로세스 자체에서 행을 완전히 기록하도록 하고 출력 버퍼링을 비활성화하는 것이 더 쉬운 방법일 수 있습니다 write. 파이프 PIPE_BUF. 예를 들어 다음을 보장할 수 있습니다.하다출력 버퍼링을 사용하고 stdio한 줄 또는 여러 줄 fflush또는 이에 상응하는 내용을 작성한 후 호출하십시오.python

Python 스크립트를 수정할 수 없는 경우 다음을 수행할 수 있습니다.

lb() { grep --line-buffered '^'; }

(GNU grep 사용) 또는:

lb() while IFS= read -r l; do printf '%s\n' "$l"; done

(명령 출력이 텍스트가 아닌 경우 아래 설명의 참고 사항을 참조하세요.)

그리고 다음을 수행하십시오:

(./handle_1.py | lb & ./handle_2.py | lb & ./handle_3.py | lb) | sort -n

이 3가지 프로세스를 피하는 lb또 다른 옵션 은 select/를 사용하는 명령에 3개의 파이프를 사용하여 poll출력이 어디에서 오는지 확인하고 이를 sort라인 기반 출력에 공급하는 것입니다. 그러나 여기에는 약간의 프로그래밍이 필요합니다.

답변4

Flowbok의 답변이 올바른 해결책입니다. 이상하게도 GNU의 출력은 parallel파일로 직접 출력되는 경우 손상되지만 tty로 출력되는 경우에는 손상되지 않습니다.

다행히도 script -ctty를 모방하는 것이 가능합니다.

여전히 세 개의 스크립트:

#!/bin/bash
# handle_1.sh
while true; do echo "1-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_2.sh
while true; do echo "2-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_3.sh
while true; do echo "3-$RANDOM$RANDOM$RANDOM$RANDOM"; done

그런 다음 병렬 처리 호출을 캡슐화하는 파일이 있습니다.

#!/bin/bash
# run_parallel.sh
parallel -u -I N ./handle_N.sh ::: "1" "2" "3"

그런 다음 다음과 같이 부릅니다.

script -c ./run_parallel > output

출력의 줄은 서로 다른 스크립트의 출력 사이에서 한 줄씩 혼합되지만 주어진 줄에서 끊어지거나 인터리브되지는 않습니다.

이상한 행동 parallel- 버그 보고서를 제출할 수 있습니다.

관련 정보