표준 입력에서 파일 목록을 처리하는 작업이 있습니다. 프로그램을 시작하는 데 시간이 오래 걸리며, 소요 시간은 파일마다 크게 다릅니다. 나는 이러한 프로세스를 많이 생성한 다음 사용 중이 아닌 프로세스에 작업을 할당하고 싶습니다. 내가 원하는 것을 거의 수행하는 몇 가지 명령줄 도구가 있었고 거의 작동한 두 가지 옵션으로 범위를 좁혔습니다.
find . -type f | split -n r/24 -u --filter="myjob"
find . -type f | parallel --pipe -u -l 1 myjob
문제는 split
순전히 루핑이므로 프로세스 중 하나가 뒤쳐져 전체 작업 완료를 지연시키는 동시에 parallel
N 라인 또는 N 바이트 입력마다 프로세스를 생성하려고 한다는 것입니다. 시작 오버헤드 시간이 너무 많이 걸렸습니다.
프로세스를 재사용하고 차단되지 않은 표준 입력을 사용하여 프로세스에 라인을 공급하는 유사한 것이 있습니까?
답변1
GNU Parallel의 경우 --block을 사용하여 블록 크기를 설정할 수 있습니다. 그러나 실행 중인 각 프로세스에 대해 메모리에 1블록을 유지하려면 충분한 메모리가 필요합니다.
이것이 정확히 귀하가 찾고 있는 것이 아니라는 것을 알고 있지만 현재로서는 허용 가능한 해결 방법일 수 있습니다.
작업에 평균적으로 동일한 시간이 소요된다면 mbuffer를 사용할 수 있습니다.
find . -type f | split -n r/24 -u --filter="mbuffer -m 2G | myjob"
답변2
일반적인 경우에는 불가능해 보입니다. 즉, 각 프로세스에는 버퍼가 있으며 외부에서 버퍼를 관찰하여 다음 항목을 어디에 넣을지 결정할 수 있습니다(스케줄링)... 물론 무언가를 작성할 수 있습니다(또는 slurm 과 같은 배치 시스템을 사용할 수 있음).
그러나 프로세스에 따라 입력을 전처리할 수도 있습니다. 예를 들어, 파일을 다운로드하거나, 데이터베이스에서 항목을 업데이트하거나, 그 중 50%가 건너뛰게 되는 경우(따라서 입력에 따라 처리에 큰 차이가 있음), 설정만 하면 됩니다. 어떤 항목이 오랜 시간이 걸릴지(파일이 존재하는지, 데이터가 변경되었는지 등) 검증하는 전처리기가 있으므로 반대쪽에서 오는 모든 항목에는 상당히 동일한 시간이 소요됩니다. 휴리스틱이 완벽하지 않더라도 아마도 상당한 진전을 이룰 수 있을 것입니다. 다른 파일을 파일로 덤프하고 동일한 방식으로 처리할 수 있습니다.
그러나 사용 사례에 따라 다릅니다.
답변3
아니요, 보편적인 해결책은 없습니다. 스케줄러는 각 프로그램이 언제 다른 행을 읽을 준비가 되었는지 알아야 하지만, 내가 아는 한 이를 허용하는 표준은 없습니다. 당신이 할 수 있는 일은 STDOUT에 라인을 추가하고 파이프에서 생산자가 그것을 소비할 때까지 기다리는 것뿐입니다. 실제로 다음 컨슈머가 준비되었는지 알 수 있는 좋은 방법은 없습니다.
답변4
이 시도:
mkfifo
모든 프로세스에 대해.
그런 다음 tail -f | myjob
각 fifo에 매달립니다.
예를 들어 작업자 설정(myjob 프로세스)
mkdir /tmp/jobs
for X in 1 2 3 4
do
mkfifo pipe$X
tail -f pipe$X | myjob &
jobs -l| awk '/pipe'$X'/ {print $2, "'pipe$X'"}' >> pipe-job-mapping
done
애플리케이션(myjob)에 따라 jobs -s를 사용하여 중지된 작업을 찾을 수 있습니다. 그렇지 않으면 CPU별로 정렬된 프로세스를 나열하고 가장 적은 리소스를 소비하는 프로세스를 선택합니다. 예를 들어 추가 작업이 필요할 때 파일 시스템에 플래그를 설정하여 작업 보고서 자체를 만듭니다.
입력을 기다리는 동안 작업이 중지되었다고 가정하면 다음을 사용하십시오.
jobs -sl
예를 들어, 중지된 작업의 pid를 찾아 작업을 할당합니다.
grep "^$STOPPED_PID" pipe-to-job-mapping | while read PID PIPE
do
cat workset > $PIPE
done
나는 이것을 테스트했다
garfield:~$ cd /tmp
garfield:/tmp$ mkfifo f1
garfield:/tmp$ mkfifo f2
garfield:/tmp$ tail -f f1 | sed 's/^/1 /' &
[1] 21056
garfield:/tmp$ tail -f f2 | sed 's/^/2 /' &
[2] 21058
garfield:/tmp$ echo hello > f1
1 hello
garfield:/tmp$ echo what > f2
2 what
garfield:/tmp$ echo yes > f1
1 yes
나는 이것이 단지 조작된 것임을 인정해야 합니다. 그래서 ymmv.