
Mac Pro 2010/Mojarve OS에서 실행하는 다음 작업 BASH 스크립트가 있습니다.
#!/bin/bash
c=0
cnt=0
# count up wav files
cnt=$(find /hummdinger/LoCI/LoCI_orig/VO/WAV_Processed/ -name "*.wav" | wc -l)
echo "there are $cnt .wav voice samples."
# go through and run rhubarb on them
for f in $(find /hummdinger/LoCI/LoCI_orig/VO/WAV_Processed/ -name "*.wav")
do
c=$((c+1))
echo "$c of $cnt";
f=$(basename "$f" .wav)
/hummdinger/LoCI/LoCI_orig/TSV/rhubarb-lip-sync-1.10.0-osx/rhubarb /hummdinger/LoCI/LoCI_orig/VO/WAV_Processed/"$f".wav -o /hummdinger/LoCI/LoCI_orig/LOCI_GAME_FILES/Compiled/Windows/sync/"$f".tsv
done;
WAV 파일 목록을 가져와 각각을 살펴보고 파일을 스캔한 다음 출력을 생성하고 생성된 TSV 파일을 다른 곳에 저장합니다. '대황'의 핵심은 녹음(WAV 파일)에서 립싱크 정보를 생성하는 것입니다. 등등 등등 어쩌구 저쩌구.
이 스크립트의 한 가지 문제점은 약 3,000개의 wav 파일을 실행하는 데 ~10-12시간이 걸린다는 것입니다. 내 형편없는 비 ECC 램, 한 번은 완전히 손상되었고 다시는 사용하지 않겠다고 맹세한 Mac Mini 2018에서는 약 1시간이 걸렸습니다.삼시간.
하지만 이것은 Mac Pro입니다. 즉, 오래되었지만(2010년) 매우 안정적이며 12x Xeon을 갖추고 있습니다. 이것은 강도가 매우 낮은 작업이므로 단일 프로세서로 만들면 추가 혜택을 놓치게 됩니다. 저는 이 스크립트를 10-15-30개의 스레드로 작업하고 싶습니다. 이렇게 하면 속도가 빨라지고 한 시간 이내에 완료될 수 있기를 바랍니다. 대부분의 날은 아닙니다.
내 생각은 다음과 같습니다. WAV 디렉터리를 (total_files/15) 그룹으로 나누고 이 목록을 file1-15.txt에 넣은 다음 각 항목을 다시 읽고 15개의 개별 스레드에서 처리합니다. 하지만 제가 얻은 것은 여기까지입니다 :P
누구든지 이것을 다중 프로세스 스크립트로 만드는 데 도움을 줄 수 있습니까? 저는 아마추어이고 reddit의 도움을 받아 이 스크립트를 만들었습니다.
답변1
GNU Parallel을 사용하면 다음과 같은 작업을 수행할 수 있습니다.
rhubarb=/hummdinger/LoCI/LoCI_orig/TSV/rhubarb-lip-sync-1.10.0-osx/rhubarb
find /hummdinger/LoCI/LoCI_orig/VO/WAV_Processed/ -name "*.wav" |
parallel $rhubarb {} -o {.}.tsv
또는 (다른 디렉토리에 출력이 정말로 필요한 경우):
find /hummdinger/LoCI/LoCI_orig/VO/WAV_Processed/ -name "*.wav" |
parallel $rhubarb {} -o /hummdinger/LoCI/LoCI_orig/LOCI_GAME_FILES/Compiled/Windows/sync/{/.}.tsv
답변2
인수를 반복하도록 스크립트를 작성하십시오. 예를 들어:
#!/bin/bash
rhubarb='/hummdinger/LoCI/LoCI_orig/TSV/rhubarb-lip-sync-1.10.0-osx/rhubarb'
outdir='/hummdinger/LoCI/LoCI_orig/LOCI_GAME_FILES/Compiled/Windows/sync/'
for fn in "$@"; do
bn=$(basename "$fn" .wav)
"$rhubarb" "$fn" -o "$outdir/$bn.tsv"
done
예를 들어 이것을 다른 이름 myscript1.sh
으로 저장하고 chmod +x myscript1.sh
.
이를 직접 실행할 수 있지만 각 파일을 순차적으로 처리합니다. 대신 GNU parallel
또는 xargs -P
. 예를 들어 처리할 파일 수를 보유한 코어 수로 나누는 다음과 같은 래퍼 스크립트를 사용합니다.
정확히 무엇을 하는지에 따라 rhubarb
이는 CPU 바인딩보다 I/O 바인딩 작업에 더 가깝기 때문에 너무 많은 코어를 추가하는 것은 도움이 되지 않을 것입니다. 실제로 작업 속도가 느려질 수 있습니다. 디스크 I/O에 대한 경합이 너무 많습니다. 특히 SSD가 아닌 HDD에서 실행하는 경우 더욱 그렇습니다.
내가 사용하는 것보다 아래 스크립트에 cores=4
또는 같은 것을 하드 코딩하고 싶을 수도 있습니다 . (나는 16개의 코어와 32개의 스레드가 있는 threadripper 1950x를 실행하고 있기 때문에 그렇게 썼습니다....그리고 원하지 않았습니다. 32개의 작업을 병렬로 실행하는 방법도 있습니다. 또한 에서 유용한 정보를 추출하는 방법의 예이기도 합니다 .cores=8
lscpu | awk ...
lscpu
또한 권장 사항: 드라이브가 두 개 이상인 경우 .wav 파일을 읽는 디렉터리가 한 드라이브에 있고 .tsv 파일을 쓰는 디렉터리가 다른 드라이브에 있도록 항목을 정렬해 보세요. 이렇게 하면 파일 읽기와 쓰기 사이의 I/O 경합이 제거됩니다. .tsv 파일이 크지 않으면 tmpfs 램디스크의 임시 디렉터리에 쓰고 스크립트 끝의 최종 위치로 이동합니다.
#!/bin/bash
wavdir="$1"
cores=$(lscpu | awk -F': +' '/^CPU\(s\):/ {cpus=$2};
/^Thread\(s\) per core:/ {tpc=$2};
END { print int(cpus / tpc) }')
count=$(find "$wavdir" -type f -name "*.wav" -print0 |
perl -0ne '$c++;END{print $c}')
let files_per_thread=count/cores
find "$wavdir" -type f -name "*.wav" -print0 |
xargs -0 -r -L "$files_per_thread" -P "$cores" /path/to/myscript1.sh
예를 들어 이것을 다른 이름 myscript2.sh
으로 저장하고 chmod +x myscript2.sh
.
이것은 명령줄이나 cron 등에서 실행하는 스크립트입니다. 차례로 xargs
여러 인스턴스를 myscript1.sh
병렬로 실행하는 데 사용됩니다.
다음과 같이 실행하세요:
./myscript2.sh /hummdinger/LoCI/LoCI_orig/VO/WAV_Processed/
그런데, 이는 파일 이름 사이의 구분 기호로 NUL을 사용하므로 모든 파일 이름에 사용하는 것이 안전합니다(개행 문자를 파일 이름 구분 기호로 사용하는 것은 파일 이름 내에서 유효한 문자이기 때문에 개행 문자를 사용하는 것은 안전하지 않습니다).