BASH 루프, 카운터, 하위 프로세스 카운터가 작동하지 않습니다.

BASH 루프, 카운터, 하위 프로세스 카운터가 작동하지 않습니다.
  • 질문:상위 스크립트가 무작위로 너무 많은 작업자 스크립트를 생성합니다.
  • 의심하다: bash 버그가 있지만 인식할 수 없습니다.
  • 운영 체제:우분투 16.04.03 LTS
  • GNU 배쉬:버전 4.3.48(1) - 출시됨(x86_64-pc-linux-gnu)
  • MySQL:5.7.21(MySQL 저장소)

상위 스크립트의 역할은 MySQL에서 데이터를 가져와서 MySQL의 데이터를 사용하여 백그라운드에서 작업자 스크립트를 실행하는 것입니다. 상위 스크립트는 모든 데이터가 처리될 때까지 7개 이하의 작업자 스크립트를 실행하는 일을 담당합니다. 이 방법은 약 한 달 전까지 수년간 완벽하게 작동했습니다. 내 문제가 최근 업데이트로 인해 발생한 것으로 의심됩니다. 논리는 다음과 같습니다.

  1. 상위 스크립트는 MySQL 서버에서 데이터를 가져옵니다.
  2. 상위 스크립트는 백그라운드에서 반복되고 작업자 스크립트를 시작하여 MySQL에서 얻은 데이터를 전달합니다.
  3. 작업 스크립트는 "잠금 파일"을 생성하고 씁니다.
  4. 상위 스크립트는 생성된 작업자 스크립트 수와 작업자 잠금 파일 수를 모니터링하여 최대 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)

관련 정보