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


10

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

이 Python 스크립트는 느리고 CPU에 바인딩되어 있으므로 (멀티 코어 머신의 단일 코어에) 각 데이터 유형마다 하나씩 3 개의 인스턴스를 실행하고 출력을 결합하여 전달하려고합니다 sort. 기본적으로 다음과 같습니다.

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

그러나 세 개의 스크립트가 동시에 실행됩니다.

스트림을 처리하는 스크립트의 n 인스턴스간에 stdout 스트림을 라운드 로빈하는 데 GNU 가 사용 된 이 질문을 발견 했습니다split .

split 맨 페이지에서 :

-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; }

불행히도, 나는 줄이 서로 섞여 있고 거기에 있어서는 안되는 많은 줄 바꿈이 보입니다.

예를 들어 파이썬 스크립트를 간단한 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인수를 제거하면 작동 하지만 버퍼링되고 스크립트 중 하나를 제외한 모든 출력을 버퍼링하므로 메모리가 부족합니다.

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


freenode에서 #bash의 일부 사람들은 세 가지 프로세스를 모두 생성하고 배경을 지정하고 사용자 지정 FD에 작성 한 다음 해당 FD를 반복하고 해당 행을 읽도록 제안했지만 해당 작업을 수행하는 방법을 찾지 못했습니다. 나는 또한 coprocbash에 내장 된 것을 보라고 들었지만 실제로 어떻게 적용되는지는 알지 못한다.
Cera

1
중간 파일없이해야합니까? 당신은 그냥 할 수 job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3없습니까?
angus

답변:


2

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

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

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


나는 혼란 조금 해요 - (가) 있습니다 X에서 IX말하는 -I그 X는 대체 플래그 것, 또는이 적용되어 -X겉으로도 관련 의미가 플래그를?
Cera

흠. 나는 이것을하고있다 : parallel -u -X ./handle_{}.sh ::: "1" "2" "3"그리고 불행히도 나는 여전히 출력 맹 글링을보고있다.
Cera

전자 : 당신은 또한 사용할 수 parallel -u ./handle_{}.sh있지만 중괄호는 (질문과 같이) 명령을 결합하는 의미를 갖기 때문에 변경하는 것을 선호합니다.
flowblok

나를 위해 작동하는 것 같습니다, 내 grep이 맹글 거리지 않습니다 : pastie.org/5113187 (테스트 bash 스크립트 또는 실제 Python 스크립트를 사용하고 있습니까?)
flowblok

문제는 그것이 실제로 병렬로 아무것도하지 않는다는 것입니다. bash 스크립트를 사용하고 있습니다 -pastie.org/5113225
Cera

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를 사용하지 마십시오.

순서를 유지하려면 모든 handle_1 출력이 handle_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을 출력을 보유 할만큼 큰 디렉토리로 설정하십시오.


1
출력 '혼합'을 원합니다. 최종 출력의 모든 줄이 하위 프로세스 중 하나의 단일 줄인지 확인하고 싶습니다. 혼합하지 않으면 시스템에 아직 인쇄되지 않은 stdout 스트림을 버퍼링하는 메모리가 부족합니다.
Cera

GNU Parallel을 사용하면 메모리가 부족하지 않습니다. 메모리에 버퍼링되지 않습니다. 왜 메모리에 버퍼링한다고 생각합니까?
Ole Tange

2

어쩌면 내가 뭔가를 잃어 버렸지 만 할 수는 없습니다.

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

각 프로세스의 라인을 인터리브하지 않으려면 프로세스 자체가 완전히 작성하고 write파이프에 대한 s 가보다 크지 않은 한 원자로 유지되도록 출력 버퍼링을 비활성화하는 것이 더 쉽습니다. PIPE_BUF. 예를 들어, 당신은 확실히 그것을 만들 수 않습니다 라 유스 출력 버퍼링을 stdio하고 전화 fflush또는 무엇이든 동등한에 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/ poll를 사용 하여 출력이 어디에서 나오는지 확인하고 출력을 sort라인 기반으로 공급하는 하나의 명령에 3 개의 파이프를 두는 것이지만 약간의 프로그래밍이 필요합니다.


당신 wait은 거기에 필요 하다고 생각합니다.
derobert

1
파이프 sort -n가 열려 있고 fd가 열려있는 모든 프로그램이 종료 될 때까지 남아 있기 때문에 일부 프로그램이 종료하기 전에 stdout을 닫지 않으면 안됩니다 .
Stéphane Chazelas

사실, 나는 시험했다, 당신은 맞습니다.
derobert

아니요, 여전히 엉망이됩니다. 라인이 혼합되어 인터리브됩니다.
Cera

1
OK @Cerales, 내 업데이트 된 답변보기
Stéphane Chazelas

1

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-버그 신고서를 제출할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.