Использование mkfifo для управления параллельными потоками

#multithreading #shell

Вопрос:

Я использую mkfifo, чтобы попытаться управлять количеством одновременных фоновых задач, выполняемых сценарием оболочки. У меня есть счетчик, который управляет начальным набором задач при развертывании, но после этого я получаю список pid в mkinfo для отслеживания child_pids, запускающих новую задачу, когда она завершается. Где сценарий терпит неудачу, так это в том, что он ожидает первого/следующего pid в списке FIFO. Некоторые потоки могут занять очень много времени по сравнению с другими, которые «начались позже». Это оставляет мне много времени, когда задача не выполняет максимальное количество потоков. Что часто случается, так это то, что он наматывает много потоков, а затем ничего не делает, когда застревает в длинном потоке. Когда длительный поток, наконец, завершается, он часто добавляет сразу много новых потоков, так как идентификаторы pid в списке позже уже завершены. Это не очень эффективно. Есть ли способ, чтобы это отслеживало количество pid? Чтобы сделать это, я думаю, мне нужно, чтобы дочерняя задача в фоновом режиме удалялась из списка pid по мере ее завершения? Или, может быть, просто попросите «задачу ожидания» повторять все pid каждые несколько секунд, чтобы увидеть, завершены ли какие-либо из них. Есть ли лучший способ написать это?

 cpus_still_running=0
number_of_cpus=20 #max number of threads
run=$secnum
myfifo=$(/bin/mktemp --dry-run) 
mkfifo --mode 0700 $myfifo   
exec 3<>$myfifo  
rm -f $myfifo  


# run through all the instruments being tested, starting with the last
while [ $run -gt 0 ] ; do
  while (( $cpus_still_running >= $num_of_cpus )) ; do # this stays at 20 almost whole time task runs after initial spool up
    if read -u 3 child_pid ; then                        
      wait $child_pid.   #this is the part that waits until one specific pid to close before starting more tasks
      (( cpus_still_running -- )). #doesnt really do much as this count stays basically maxed after spool up
    fi
  done

( # child process 
  case "$@" in 

  ALL ) 
     # do a bunch of stuff using $run to make task unique

  SMALL_RUN ) 
     #do a bunch of stuff using $run to make task unique
    ;;
  esac
  echo $! 1>amp;3  #writes out the child pid
) amp;
(( cpus_still_running    ))
(( run -- ))
done
wait