2011-06-28 10 views
21

Mi pregunta es cómo cambiar este código por lo que utilizará solo 4 subprocesos/subprocesos?Cómo limitar el número de subprocesos/subprocesos utilizados en una función en bash

TESTS="a b c d e" 

for f in $TESTS; do 
    t=$[ ($RANDOM % 5) + 1 ] 
    sleep $t && echo $f $t & 
done 
wait 
+15

Estas no son las discusiones, pero subprocesos. –

+2

¿Podría considerar aceptar una respuesta y cambiar los "hilos" por "subprocesos" en su pregunta? ¡Usar las palabras incorrectas hace que sea más difícil encontrarlo en la web! ;-) – Peque

Respuesta

5

Usted puede hacer algo como esto utilizando el jobs orden interna:

for f in $TESTS; do 
    running=($(jobs -rp)) 
    while [ ${#running[@]} -ge 4 ] ; do 
    sleep 1 # this is not optimal, but you can't use wait here 
    running=($(jobs -rp)) 
    done 
    t=$[ ($RANDOM % 5) + 1 ] 
    sleep $t && echo $f $t & 
done 
wait 
0

Este script probado corre 5 puestos de trabajo a la vez y se reiniciará un nuevo trabajo tan pronto como lo hace (debido a la matar el sueño de 10,9 cuando tenemos una SIGCHLD. una versión más simple de esto podría utilizar de votación directa (10,9 cambiar el sueño de dormir 1 y deshacerse de la trampa).

#!/usr/bin/bash 

set -o monitor 
trap "pkill -P $$ -f 'sleep 10\.9' >&/dev/null" SIGCHLD 

totaljobs=15 
numjobs=5 
worktime=10 
curjobs=0 
declare -A pidlist 

dojob() 
{ 
    slot=$1 
    time=$(echo "$RANDOM * 10/32768" | bc -l) 
    echo Starting job $slot with args $time 
    sleep $time & 
    pidlist[$slot]=`jobs -p %%` 
    curjobs=$(($curjobs + 1)) 
    totaljobs=$(($totaljobs - 1)) 
} 

# start 
while [ $curjobs -lt $numjobs -a $totaljobs -gt 0 ] 
do 
    dojob $curjobs 
done 

# Poll for jobs to die, restarting while we have them 
while [ $totaljobs -gt 0 ] 
do 
    for ((i=0;$i < $curjobs;i++)) 
    do 
    if ! kill -0 ${pidlist[$i]} >&/dev/null 
    then 
     dojob $i 
     break 
    fi 
    done 
    sleep 10.9 >&/dev/null 
done 
wait 
32

questi interesante en. Intenté usar xargs para esto y encontré la manera.

Prueba esto:

seq 10 | xargs -i --max-procs=4 bash -c "echo start {}; sleep 3; echo done {}" 

--max-procs=4 se asegurará de que no más de cuatro subprocesos se ejecutan a la vez.

La salida tendrá el siguiente aspecto:

start 2 
start 3 
start 1 
start 4 
done 2 
done 3 
done 1 
done 4 
start 6 
start 5 
start 7 
start 8 
done 6 
done 5 
start 9 
done 8 
done 7 
start 10 
done 9 
done 10 

Tenga en cuenta que el orden de ejecución podría no seguir las órdenes en el orden en que se envía. Como se puede ver 2 comenzó antes 1.

13

solución rápida y sucia: insertar esta línea en algún lugar dentro de su for bucle:

while [ $(jobs | wc -l) -ge 4 ] ; do sleep 1 ; done 

(asume que no lo tiene otros trabajos en segundo plano que se ejecutan en la misma consola)

+4

esto podría ser un poquito más eficiente con 'jobs -r' - sin él, contarás las líneas donde bash te dice qué trabajos ya están hechos. – Mat

+0

Esta solución es genial. ¡Solo inserto la línea en el lugar correcto y boom! Me gustó que no necesité cambiar la estructura de mi script en absoluto –

7

he encontrado otra solución para esta pregunta utilizando parallel (parte de moreutils paquete.)

parallel -j 4 -i bash -c "echo start {}; sleep 2; echo done {};" -- $(seq 10) 

-j 4 representa -j maxjobs

-i utiliza los parámetros como {}

-- delimita sus argumentos

La salida de este comando será:

start 3 
start 4 
start 1 
start 2 
done 4 
done 2 
done 3 
done 1 
start 5 
start 6 
start 7 
start 8 
done 5 
done 6 
start 9 
done 7 
start 10 
done 8 
done 9 
done 10 
Cuestiones relacionadas