이 질문은 나에게 큰 영감을 주었습니다.Bash FOR 루프 병렬화 읽기 루프 동안 매우 긴 작업을 포함하는 일부 도구를 병렬화합니다(즉, 입력 파일의 지정된 경로에서 동일한 작업/작업 집합을 실행합니다. 입력 파일에는 약 90,000줄이 포함되며 계속해서 증가합니다).
PSkocik의 "FIFO 기반 세마포어를 사용하는 N 프로세스" 예제를 내 코드에 "삽입"하는 모든 작업을 완료했습니다...
# initialize a semaphore with a given number of tokens
open_sem(){
mkfifo /tmp/pipe-$$
exec 3<>/tmp/pipe-$$
rm /tmp/pipe-$$
local i=$1
for((;i>0;i--)); do
printf %s 000 >&3
done
}
# run the given command asynchronously and pop/push tokens
run_with_lock(){
local x
# this read waits until there is something to read
read -u 3 -n 3 x && ((0==x)) || exit $x
(
( "$@"; )
# push the return code of the command to the semaphore
printf '%.3d' $? >&3
)&
}
N=4
open_sem $N
for thing in {a..g}; do
run_with_lock task $thing
done
그러나 내 "이전" 코드에는 읽기 루프에 멋진 진행률 카운터가 내장되어 있으며(아래 코드는 축약됨) 그렇습니다. 재사용하려는 경향이 있는 echo, awk 및 printf의 이상한 조합이 있다는 것을 알고 있습니다. 사용된 다른 스크립트의 코드는 다른 온라인 예제 등을 기반으로 할 수 있습니다. 정리할 수 있다고 확신합니다... 하지만 작동하며 이 코드를 사용하는 유일한 사람입니다! :
## $temp1 is the file with 90,000 lines to read over
## $YELLOW is a global variable exported from my bashrc with the escape code for yellow text
## $GREEN is a global variable exported from my bashrc with the escape code for green text
## $CL is a global variable exported from my bashrc with the escape code for Clear Line
## $NC is a global variable exported from my bashrc with the escape code to revert text colour back to normal
num_lines="$(cat $temp1 | wc -l)"
percent_per_line="$(awk "BEGIN {print 100/$num_lines}")"
progress_percent='0'
current_line='1'
echo -ne "${CL}${YELLOW}PROGRESS: ${progress_percent}% ${NC}\r"
while read line; do
############################################
##commands to process $line data as needed##
############################################
progress_percent="$(awk "BEGIN {print $progress_percent + $percent_per_line }")"
awk -v y=$YELLOW -v nc=$NC -v progress=$progress_percent -v current_line=$current_line -v total_lines=$num_lines 'BEGIN {printf (y"\033[2KPROGRESS: %.3f%% (%d OF %d)\n\033[1A"nc, progress, current_line, total_lines) }'
#I think I mixed my global var escape codes with typed out ones cause I was I forgot / have no need to export \033[2K and \033[1A for anything else?
((current_line++))
done < "$temp1"
echo -e "${CL}${GREEN}PROGRESS: 100.000% (${num_lines} OF ${num_lines})${NC}"
"새로운" FIFO 세마포어 코드에 비슷한 출력을 가진 무언가를 다시 집어넣는 방법을 찾으려고 노력 중입니다...
난 그냥 무엇을 해야할지 모르겠어요! run_with_lock 함수로 들어가나요? 그렇다면 어디에서 rates_per_line 및 num_lines 변수를 해당 함수에 전달해야 하지만 $@
거기로 전달됩니다. :( FIFO 세마포어가 작동하는 방식을 완전히 이해하지 못하는 것 같습니다. 필요한 데이터를 전달하기 위해 다른 세마포어 메시지 유형을 사용하는 경우에도 마찬가지입니다.
제가 배우고 발전하는 데 도움이 되므로 어떤 도움이라도 대단히 감사하겠습니다!
답변1
좋아, 그래서 바보 같은 느낌이 든다... 100% 정확하지는 않지만 간단한 테스트 스크립트로 많은 테스트를 마친 후에는 처리해야 할 것 같은 느낌이 든다.
나는 전체 세마포어의 정확한 기능적 방법을 "인식"하지 못했습니다. 내가 보는 방식은 while read
루프가 모든 "읽기"를 한 번에 수행하고 모든 행을 일부 대기열(내 생각에는 파이프)에 추가한다는 것입니다. 그래서 처음 생각은 루프의 다른 항목을 읽는 것도 "완전히" 실행된다는 것이었습니다. (즉, 즉시 100%로 점프) 스크립트는 wait
읽기 루프 이후에 대기열을 완료하기 위해 이동하며, 실제로는 여전히 작업을 수행하고 있음에도 불구하고 100% 완료라는 터미널 화면이 표시됩니다.
내가 더 이상 틀릴 수는 없다는 것이 밝혀졌습니다! 즉 run_with_lock
, 루프는 while read
한 번에 행만 읽으므로 호출 이후의 모든 코드는 잠금이 해제될 때 간헐적으로만 실행됩니다.N
run_with_lock
따라서 목표를 달성하기 위해 해야 할 일은 진행 코드를 정확히 같은 위치에 유지하는 것뿐입니다. 그러면 모든 것이 정상입니다. 제 생각에는 특별한 처리가 필요하지 않습니다.
단점은 이제 항목이 실제로 완료되면 업데이트하는 대신 작업이 시작될 때 진행 상황이 표시된다는 것입니다. 그러나 이는 필요한 항목에 비해 미미합니다.