- 질문:상위 스크립트가 무작위로 너무 많은 작업자 스크립트를 생성합니다.
- 의심하다: bash 버그가 있지만 인식할 수 없습니다.
- 운영 체제:우분투 16.04.03 LTS
- GNU 배쉬:버전 4.3.48(1) - 출시됨(x86_64-pc-linux-gnu)
- MySQL:5.7.21(MySQL 저장소)
상위 스크립트의 역할은 MySQL에서 데이터를 가져와서 MySQL의 데이터를 사용하여 백그라운드에서 작업자 스크립트를 실행하는 것입니다. 상위 스크립트는 모든 데이터가 처리될 때까지 7개 이하의 작업자 스크립트를 실행하는 일을 담당합니다. 이 방법은 약 한 달 전까지 수년간 완벽하게 작동했습니다. 내 문제가 최근 업데이트로 인해 발생한 것으로 의심됩니다. 논리는 다음과 같습니다.
- 상위 스크립트는 MySQL 서버에서 데이터를 가져옵니다.
- 상위 스크립트는 백그라운드에서 반복되고 작업자 스크립트를 시작하여 MySQL에서 얻은 데이터를 전달합니다.
- 작업 스크립트는 "잠금 파일"을 생성하고 씁니다.
- 상위 스크립트는 생성된 작업자 스크립트 수와 작업자 잠금 파일 수를 모니터링하여 최대 7개의 작업자 스크립트를 계속 실행합니다.
나는 하위 프로세스가 잠금 파일을 설정하고 쓸 시간을 갖기 전에 상위 스크립트가 여러 하위 프로세스를 반복하고 생성할 수 있다는 것을 알고 있습니다. 이것이 바로 제가 이러한 상황을 방지하기 위해 하위 생성 수(SPWNCNT)를 유지하는 이유입니다. 내가 말했듯이 예전에는 잘 작동했지만 더 이상은 작동하지 않습니다.
이것은 스크립트의 일부입니다.
#!/bin/bash
......
###########################
# Loop through all unique codes and process them.
echo "$0: NOTICE: Started processing codes; `date`."
COMCNT=0
SPWNCNT=0
TPCNT=0
while read COMNUM
do
# Only permit a certain number of child processes
# so to not overload the machine or chew up to
# many MySQL connections.
PCNT=`ls -1 $TEMPDIR/*.Worker.lock 2>/dev/null | wc -l`
(( TPCNT = PCNT + SPWNCNT ))
TPCNT=`echo ${TPCNT#-}`
while [[ $TPCNT -gt 6 ]]
do
# Too many child processes.
sleep 1
PCNT=`ls -1 $TEMPDIR/*.Worker.lock 2>/dev/null | wc -l`
(( TPCNT = PCNT + SPWNCNT ))
TPCNT=`echo ${TPCNT#-}`
if [[ $SPWNCNT -gt 0 ]]
then
(( SPWNCNT = SPWNCNT - PCNT ))
if [[ $SPWNCNT -lt 0 ]]
then
SPWNCNT=0
fi
fi
done # while -gt 6
# Spawn a worker process
./Worker.sh $COMNUM &
(( SPWNCNT = SPWNCNT + 1 ))
(( COMCNT = COMCNT + 1 ))
if [ "$VERBOSE" = "true" ]
then
echo "$0: NOTICE: Spawned $COMNUM, count $COMCNT ($SPWNCNT); `date`"
fi
done << COMNUM_EOF
`cat $GEN_RATES_COMNUM_FILE | $MyCMD -B -N $MyDB`
COMNUM_EOF
......
다음은 문제의 디버그 출력입니다(#!/bin/bash -x 사용).
...... many lines showing same logic working correctly ......
++ wc -l
++ ls -1 '/tmp/*.Worker.lock'
+ PCNT=0
+ (( TPCNT = 0 + 7 ))
++ echo 7
+ TPCNT=7
+ [[ 7 -gt 0 ]]
+ (( SPWNCNT = 7 - 0 ))
+ [[ 7 -lt 0 ]]
+ [[ 7 -gt 6 ]]
+ sleep 1
++ wc -l
++ ls -1 /tmp/032500.Worker.lock /tmp/032800.Worker.lock
/tmp/033300.Worker.lock /tmp/033900.Worker.lock /tmp/034700.Worker.lock
/tmp/035400.Worker.lock /tmp/035600.Worker.lock /tmp/036000.Worker.lock
/tmp/036200.Worker.lock /tmp/036400.Worker.lock /tmp/036600.Worker.lock
/tmp/037000.Worker.lock /tmp/039100.Worker.lock /tmp/039600.Worker.lock
/tmp/040200.Worker.lock /tmp/040400.Worker.lock /tmp/041000.Worker.lock
/tmp/041200.Worker.lock /tmp/041600.Worker.lock /tmp/041800.Worker.lock
/tmp/042000.Worker.lock /tmp/043600.Worker.lock /tmp/046200.Worker.lock
/tmp/048600.Worker.lock /tmp/049600.Worker.lock /tmp/052000.Worker.lock
/tmp/052300.Worker.lock /tmp/054300.Worker.lock /tmp/054500.Worker.lock
/tmp/054900.Worker.lock /tmp/055300.Worker.lock /tmp/056000.Worker.lock
/tmp/056200.Worker.lock
/tmp/056600.Worker.lock /tmp/056900.Worker.lock /tmp/057800.Worker.lock
/tmp/058600.Worker.lock /tmp/060400.Worker.lock /tmp/060700.Worker.lock
+ PCNT=39
+ (( TPCNT = 39 + 7 ))
++ echo 46
+ TPCNT=46
+ [[ 7 -gt 0 ]]
+ (( SPWNCNT = 7 - 39 ))
+ [[ -32 -lt 0 ]]
+ SPWNCNT=0
+ [[ 46 -gt 6 ]]
+ sleep 1
++ wc -l
++ ls -1 /tmp/032500.Worker.lock /tmp/032800.Worker.lock
/tmp/033300.Worker.lock /tmp/033900.Worker.lock /tmp/034700.Worker.lock
/tmp/035400.Worker.lock /tmp/035600.Worker.lock /tmp/036000.Worker.lock
/tmp/036200.Worker.lock /tmp/036400.Worker.lock /tmp/036600.Worker.lock
/tmp/037000.Worker.lock /tmp/039100.Worker.lock /tmp/039600.Worker.lock
/tmp/040200.Worker.lock /tmp/040400.Worker.lock /tmp/041000.Worker.lock
/tmp/041200.Worker.lock /tmp/041600.Worker.lock /tmp/041800.Worker.lock
/tmp/042000.Worker.lock /tmp/043600.Worker.lock /tmp/046200.Worker.lock
/tmp/048600.Worker.lock /tmp/049600.Worker.lock /tmp/052000.Worker.lock
/tmp/052300.Worker.lock /tmp/054300.Worker.lock /tmp/054500.Worker.lock
/tmp/054900.Worker.lock /tmp/055300.Worker.lock /tmp/056000.Worker.lock
/tmp/056200.Worker.lock
/tmp/056600.Worker.lock /tmp/056900.Worker.lock /tmp/057800.Worker.lock
/tmp/058600.Worker.lock /tmp/060400.Worker.lock /tmp/060700.Worker.lock
+ PCNT=39
+ (( TPCNT = 39 + 0 ))
++ echo 39
+ TPCNT=39
+ [[ 0 -gt 0 ]]
+ [[ 39 -gt 6 ]]
+ sleep 1
그렇다면 스크립트는 어떻게 7개의 실행 중인 프로세스(TPCNT)(올바른 대상)에서 39개, 그리고 46개로 점프합니까? 논리가 이것을 어떻게 허용하는지 알 수 없으며 디버그 출력은 bash 쉘이 떨어지는 것 외에는 이에 대한 설명을 제공하지 않는 것 같습니다.
답변1
나중에 이 게시물을 찾는 사람들을 위해...이것은 내 솔루션을 기반으로 합니다.모듈식응답은 위와 같습니다.모듈식실제로 칭찬받을 가치가 있습니다.
#!/bin/bash
.....
# Intialize the Child Process List (array)
CPLIST=()
# Max concurrent child processes
MAXCP=6
# Worker loop to spawn and monitor child (worker) processes
while [[ SOME-CONDITION ]]
do
# Monitor Child Process List (array)
# Ensure that we don't exceed Max Child Processes
if [[ ${#CPLIST[@]} -gt $MAXCP ]]
then
while [[ ${#CPLIST[@]} -gt $MAXCP ]]
do
sleep 1
# Check each child processes to see if it's still running.
for idx in ${!CPLIST[@]}
do
# Is child process still alive?
kill -0 ${CPLIST[$idx]} 2>/dev/null
if [[ $? -gt 0 ]]
then
# Child process is no longer running.
# Remove it from the child process list (array).
unset CPLIST[$idx]
fi # if $?
done # for idx
done # while MAXCP
fi # if MAXCP
# Spawn a child process
./MyProgram &
# Append Child Process PID to Child Process List
CPLIST=(${CPLIST[@]} $!)
done # while
.....
# (end of file)