Как считать процессы в BASH, в том числе и ТОЛЬКО запущенные?

Мне нужно запускать различные задания в фоновом режиме, используя /Cobra.

У меня 32 ядра, и я хочу оставить пару свободных, иначе моя машина станет слишком медленной, чтобы делать другие вещи.

В этом коде я проверяю количество процессов с помощью ps и запускаю только до максимального числа 30.

Тем не менее, "ps", похоже, не предоставляет информацию своевременно. Несмотря на то, что я жду 3 секунды, ps иногда объявляет количество совпадающих процессов. Это, по-видимому, когда они только начинают работать в фоновом режиме.

Есть ли способ получить лучший ответ от ps (или по-другому), единственное решение, которое у меня есть, - это спать дольше, но это немного тяжело.

#!/bin/sh
#set -x

while true
do
    NUMRUNNING=`ps | egrep FormsApplic | wc -l` 

    JOBS=`cat jobs.lst | wc -l`
    if [ $JOBS -gt 0 ]
    then

        MAXSTART=$((30-$NUMRUNNING))
        NUMTOSTART=$JOBS

        if [ $NUMTOSTART -gt $MAXSTART ]
        then
            NUMTOSTART=$MAXSTART
        fi 
        for ((i=1;i<=$NUMTOSTART;i++))
        do
            JOB=`head -n1 jobs.lst`
            echo $JOB >> /tmp/jobsStarted
            sed -i 1d jobs.lst
            /cobra $JOB &

        done

    fi

    LASTNUMRUNNING=$NUMRUNNING
    sleep 3
done

person ManInMoon    schedule 23.09.2014    source источник


Ответы (4)


ps должен немедленно перечислить процессы. Я не уверен, что у вас происходит не так, но этот скрипт имеет несколько улучшений. Главным из них является использование pgrep вместо разбора ps. Дайте мне знать, если это решит вашу проблему:

while true
do
    NUMRUNNING=$(pgrep -c FormsApplic)

    JOBS=$(wc -l jobs.lst)
    if [ "$JOBS" -gt 0 ]
    then

        MAXSTART=$((30-$NUMRUNNING))
        NUMTOSTART=$JOBS

        if [ "$NUMTOSTART" -gt "$MAXSTART" ]
        then
            NUMTOSTART="$MAXSTART"
        fi 
        for ((i=1;i<="$NUMTOSTART";i++))
        do
            JOB=$(head -n1 jobs.lst)
            echo "$JOB" >> /tmp/jobsStarted
            sed -i 1d jobs.lst
            /cobra "$JOB" &
        done

    fi

    LASTNUMRUNNING=$NUMRUNNING
    sleep 3
done
person terdon    schedule 23.09.2014

Вы можете использовать псевдофайловую систему /proc:

CURRENTLY_RUNNING=$(find /proc/[0-9]*/exe 2>/dev/null |grep cobra |wc -l)

Другой способ — создавать файл PID каждый раз при запуске /cobra и просто считать файлы. Единственная проблема — удалить PID-файл. Это может быть заархивировано скриптом-оболочкой:

/cobra.sh:

touch /var/run/cobra/run.$$
/cobra
rm /var/run/cobra/run.$$
person kryp    schedule 23.09.2014
comment
Не все операционные системы имеют файловую систему /proc. - person chepner; 23.09.2014

Вместо того, чтобы запрашивать количество процессов, поддерживайте счетчик самостоятельно.

num_running=0
while read job; do
    if [ $num_running -eq $max_start ]; then
        # wait for the oldest job to complete. Not ideal,
        # since another job might complete before that one.
        wait $(jobs -p | head -n 1)
        num_running=$((num_running  - 1))
    fi
    /cobra $JOB &
    num_running=$((num_running+1))
done < jobs.lst

Если вы используете bash 4.3, вы можете (наконец-то!) дождаться завершения произвольного задания, а не определенного подмножества всех заданий.

num_running=0
while read job; do
    if [ $num_running -eq $max_start ]; then
        # Wait for any one background job to complete
        wait -n
        num_running=$((num_running  - 1))
    fi
    /cobra $JOB &
    num_running=$((num_running+1))
done < jobs.lst
person chepner    schedule 23.09.2014

Вы можете попробовать заменить весь скрипт этой строкой:

< jobs.lst xargs -n 1 -P 30 /cobra 

Команда xargs отправляет каждую строку jobs.lst в качестве аргумента команде /cobra, создавая максимум 30 параллельных процессов.

Вот синтетический пример:

$ cat jobs.lst 
1
2
3
4

$ time < jobs.lst xargs -n 1 -P 2 sleep & 
[1] 5291
$ ps aux|grep -i [s]leep|grep -v xargs
user       5297   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 2
user       5296   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 1
$ ps aux|grep -i [s]leep|grep -v xargs
user       5297   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 2
user       5303   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 3
$ ps aux|grep -i [s]leep|grep -v xargs
user       5309   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 4
user       5303   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 3
$ ps aux|grep -i [s]leep|grep -v xargs
user       5309   0.0  0.0  2426644    320 s002  S     3:25PM   0:00.00 sleep 4
$ 
real    0m6.014s
user    0m0.002s
sys 0m0.009s

И вы можете видеть, что в каждый момент параллельно выполняются 2 задания, общее время выполнения которых составляет 2+4=6 секунд.

person damienfrancois    schedule 23.09.2014