Yanıtlar:
Nasıl olur:
prog1 & prog2 && fg
Bu irade:
prog1
.prog2
ve ön planda tutun , böylece ile kapatabilirsiniz ctrl-c
.prog2
, sen dönersiniz prog1
bireyin ön planda da yakın onunla can bu kadar, ctrl-c
.prog1
ne zaman prog2
sona erer? Düşün node srv.js & cucumberjs
prog1 & prog2 ; fg
Bu, aynı anda birden fazla ssh tüneli çalıştırmak içindi. Umarım bu birine yardımcı olur.
prog2
hemen çalışmazsa prog1
, ön planda olmaya geri döneceksiniz . Bu arzu edilirse, o zaman sorun değil.
prog1 & prog2 && kill $!
.
Şunları kullanabilirsiniz wait
:
some_command &
P1=$!
other_command &
P2=$!
wait $P1 $P2
Arka plan programı PID'lerini değişkenlere atar ( $!
son başlatılan işlem 'PID'dir), sonra wait
komut onları bekler. Güzel çünkü senaryoyu öldürürseniz, süreçleri de öldürür!
#!/usr/bin/env bash ARRAY='cat bat rat' for ARR in $ARRAY do ./run_script1 $ARR & done P1=$! wait $P1 echo "INFO: Execution of all background processes in the for loop has completed.."
${}
bir dize listesi veya benzeri içine enterpolasyon yapmak için kullanmak zorunda.
GNU Parallel http://www.gnu.org/software/parallel/ ile bu kadar kolay:
(echo prog1; echo prog2) | parallel
İsterseniz:
parallel ::: prog1 prog2
Daha fazla bilgi edin:
parallel
Farklı sözdizimine sahip farklı sürümleri olduğunu belirtmek gerekir . Örneğin, Debian türevlerinde moreutils
paket, parallel
oldukça farklı davranan adlandırılan farklı bir komut içerir .
parallel
kullanmaktan daha iyi &
?
parallel
, çekirdeklerden daha fazla iş olduğunda daha iyidir, bu durumda &
çekirdek başına bir kerede birden fazla iş çalışır. (bkz. güvercin deliği ilkesi )
Birden çok işlemi kolayca çalıştırmak ve öldürmek istiyorsanız ctrl-c
, bu benim en sevdiğim yöntemdir: bir (…)
alt kabukta birden fazla arka plan işlemi üretin ve SIGINT
yürütmek için tuzak kill 0
, alt kabuk grubunda ortaya çıkan her şeyi öldürür:
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
Karmaşık süreç yürütme yapılara sahip olabilir ve her şey yakın tek sahip olacaktır ctrl-c
(sadece yani emin geçen süreç ön planda çalıştırılan yapmak, bir içermez &
SONRA prog1.3
):
(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)
xargs -P <n>
<n>
komutları paralel olarak çalıştırmanızı sağlar .
-P
Standart olmayan bir seçenek olsa da, hem GNU (Linux) hem de macOS / BSD uygulamaları bunu destekler.
Aşağıdaki örnek:
time xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
Çıktı şöyle görünür:
1 # output from 1st command
4 # output from *last* command, which started as soon as the count dropped below 3
2 # output from 2nd command
3 # output from 3rd command
real 0m3.012s
user 0m0.011s
sys 0m0.008s
Zamanlama, komutların paralel olarak çalıştırıldığını gösterir (son komut yalnızca orijinal 3'ün ilkinden sonra başlatıldı, ancak çok hızlı bir şekilde yürütüldü).
xargs
Tüm komutlar bitinceye kadar komut kendisi döndürmez, ancak kontrol operatörü ile sonlandırarak arka planda çalıştırabilirsiniz &
kullanarak sonra ve wait
tüm beklemek yerleşiğini xargs
komutu bitirmek için.
{
xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
} &
# Script execution continues here while `xargs` is running
# in the background.
echo "Waiting for commands to finish..."
# Wait for `xargs` to finish, via special variable $!, which contains
# the PID of the most recently started background process.
wait $!
Not:
BSD / macOS xargs
, paralel olarak açıkça çalıştırılacak komut sayısını belirtmenizi gerektirirken , GNU paralel olarak olabildiğince fazla çalışmayı xargs
belirtmenize izin verir .-P 0
Paralel olarak çalışan işlemlerden elde edilen çıktı üretilirken gelir , bu nedenle beklenmedik şekilde serpiştirilir .
parallel
belirtildiği gibi, Ole'nın cevap (yok değil elverişli en platformlarla standart geliyor) serializes (grup) başına işlem bazında ve teklifler daha birçok gelişmiş özellikler üzerinde çıktı.#!/bin/bash
prog1 & 2> .errorprog1.log; prog2 & 2> .errorprog2.log
Hataları günlükleri ayırmak için yönlendirin.
prog1 2> .errorprog1.log & prog2 2> .errorprog2.log &
ls notthere1 & 2> .errorprog1.log; ls notthere2 & 2>.errorprog2.log
. Hatalar konsola gider ve her iki hata dosyası boştur. @Dennis Williamson'ın dediği gibi &
, bir ayırıcı, ;
yani, (a) komutun sonuna (herhangi bir yeniden yönlendirme işleminden sonra) gitmesi gerekiyor ve (b) hiç ihtiyacınız yok ;
:-)
Nohup çağıran çok kullanışlı bir program var.
nohup - run a command immune to hangups, with output to a non-tty
nohup
tek başına arka planda hiçbir şey çalıştırmaz ve kullanmak nohup
, arka planda görevleri çalıştırmak için bir gereklilik veya önkoşul değildir. Genellikle birlikte faydalıdırlar, ancak bu soruya cevap vermez.
Paralel olarak maksimum n işleminde (örnekte n = 4) çalıştırmak için kullandığım bir fonksiyon:
max_children=4
function parallel {
local time1=$(date +"%H:%M:%S")
local time2=""
# for the sake of the example, I'm using $2 as a description, you may be interested in other description
echo "starting $2 ($time1)..."
"$@" && time2=$(date +"%H:%M:%S") && echo "finishing $2 ($time1 -- $time2)..." &
local my_pid=$$
local children=$(ps -eo ppid | grep -w $my_pid | wc -w)
children=$((children-1))
if [[ $children -ge $max_children ]]; then
wait -n
fi
}
parallel sleep 5
parallel sleep 6
parallel sleep 7
parallel sleep 8
parallel sleep 9
wait
Max_children çekirdek sayısına ayarlanmışsa, bu işlev boş çekirdeklerden kaçınmaya çalışır.
wait -n
gerektirir bash
4.3+ ve bekleyen mantık değiştirir herhangi sonlandırmak için belirtilen / ima süreçlerin.
Geçenlerde aynı anda birden fazla program çalıştırmak, çıktılarını ayrılmış günlük dosyalarına yönlendirmek ve bitirmelerini beklemek zorunda kaldım benzer bir durum vardı ve böyle bir şey ile sona erdi:
#!/bin/bash
# Add the full path processes to run to the array
PROCESSES_TO_RUN=("/home/joao/Code/test/prog_1/prog1" \
"/home/joao/Code/test/prog_2/prog2")
# You can keep adding processes to the array...
for i in ${PROCESSES_TO_RUN[@]}; do
${i%/*}/./${i##*/} > ${i}.log 2>&1 &
# ${i%/*} -> Get folder name until the /
# ${i##*/} -> Get the filename after the /
done
# Wait for the processes to finish
wait
Kaynak: http://joaoperibeiro.com/execute-multiple-programs-and-redirect-their-outputs-linux/
Proses Yumurtlama Müdürü
Elbette, teknik olarak bunlar süreçlerdir ve bu program gerçekten bir süreç yumurtlama yöneticisi olarak adlandırılmalıdır, ancak bu sadece BASH'in ve işareti kullanarak çatalladığında çalışması nedeniyle fork () veya belki clone () sistem çağrısını kullanır. bellek paylaşacak olan pthread_create () gibi bir şey yerine, ayrı bir bellek alanına klonlar. BASH ikincisini destekleseydi, her bir "yürütme dizisi" aynı şekilde çalışır ve daha verimli bir bellek alanı elde edilirken geleneksel iş parçacıkları olarak adlandırılabilir. Bununla birlikte, her işçi klonunda GLOBAL değişkenleri bulunmadığından, kritik bölümleri yönetmek için süreçler arası iletişim dosyasının ve ilkel akın semaforunun kullanılması nedeniyle işlevsel olarak aynı çalışır, ancak biraz daha zor. Tabii ki BASH'den çatallama burada temel cevap ama sanırım insanlar bunu biliyor ama gerçekten sadece çatal ve yumurtlamak yerine yumurtladı ne yönetmek istiyoruz hissediyorum. Bu, tümü tek bir kaynağa erişen çatallı işlemlerin 200 örneğini yönetmenin bir yolunu gösterir. Açıkçası bu overkill ama ben devam etti, bu yüzden yazma zevk. Terminalinizin boyutunu buna göre artırın. Umarım bunu faydalı bulursun.
ME=$(basename $0)
IPC="/tmp/$ME.ipc" #interprocess communication file (global thread accounting stats)
DBG=/tmp/$ME.log
echo 0 > $IPC #initalize counter
F1=thread
SPAWNED=0
COMPLETE=0
SPAWN=1000 #number of jobs to process
SPEEDFACTOR=1 #dynamically compensates for execution time
THREADLIMIT=50 #maximum concurrent threads
TPS=1 #threads per second delay
THREADCOUNT=0 #number of running threads
SCALE="scale=5" #controls bc's precision
START=$(date +%s) #whence we began
MAXTHREADDUR=6 #maximum thread life span - demo mode
LOWER=$[$THREADLIMIT*100*90/10000] #90% worker utilization threshold
UPPER=$[$THREADLIMIT*100*95/10000] #95% worker utilization threshold
DELTA=10 #initial percent speed change
threadspeed() #dynamically adjust spawn rate based on worker utilization
{
#vaguely assumes thread execution average will be consistent
THREADCOUNT=$(threadcount)
if [ $THREADCOUNT -ge $LOWER ] && [ $THREADCOUNT -le $UPPER ] ;then
echo SPEED HOLD >> $DBG
return
elif [ $THREADCOUNT -lt $LOWER ] ;then
#if maxthread is free speed up
SPEEDFACTOR=$(echo "$SCALE;$SPEEDFACTOR*(1-($DELTA/100))"|bc)
echo SPEED UP $DELTA%>> $DBG
elif [ $THREADCOUNT -gt $UPPER ];then
#if maxthread is active then slow down
SPEEDFACTOR=$(echo "$SCALE;$SPEEDFACTOR*(1+($DELTA/100))"|bc)
DELTA=1 #begin fine grain control
echo SLOW DOWN $DELTA%>> $DBG
fi
echo SPEEDFACTOR $SPEEDFACTOR >> $DBG
#average thread duration (total elapsed time / number of threads completed)
#if threads completed is zero (less than 100), default to maxdelay/2 maxthreads
COMPLETE=$(cat $IPC)
if [ -z $COMPLETE ];then
echo BAD IPC READ ============================================== >> $DBG
return
fi
#echo Threads COMPLETE $COMPLETE >> $DBG
if [ $COMPLETE -lt 100 ];then
AVGTHREAD=$(echo "$SCALE;$MAXTHREADDUR/2"|bc)
else
ELAPSED=$[$(date +%s)-$START]
#echo Elapsed Time $ELAPSED >> $DBG
AVGTHREAD=$(echo "$SCALE;$ELAPSED/$COMPLETE*$THREADLIMIT"|bc)
fi
echo AVGTHREAD Duration is $AVGTHREAD >> $DBG
#calculate timing to achieve spawning each workers fast enough
# to utilize threadlimit - average time it takes to complete one thread / max number of threads
TPS=$(echo "$SCALE;($AVGTHREAD/$THREADLIMIT)*$SPEEDFACTOR"|bc)
#TPS=$(echo "$SCALE;$AVGTHREAD/$THREADLIMIT"|bc) # maintains pretty good
#echo TPS $TPS >> $DBG
}
function plot()
{
echo -en \\033[${2}\;${1}H
if [ -n "$3" ];then
if [[ $4 = "good" ]];then
echo -en "\\033[1;32m"
elif [[ $4 = "warn" ]];then
echo -en "\\033[1;33m"
elif [[ $4 = "fail" ]];then
echo -en "\\033[1;31m"
elif [[ $4 = "crit" ]];then
echo -en "\\033[1;31;4m"
fi
fi
echo -n "$3"
echo -en "\\033[0;39m"
}
trackthread() #displays thread status
{
WORKERID=$1
THREADID=$2
ACTION=$3 #setactive | setfree | update
AGE=$4
TS=$(date +%s)
COL=$[(($WORKERID-1)/50)*40]
ROW=$[(($WORKERID-1)%50)+1]
case $ACTION in
"setactive" )
touch /tmp/$ME.$F1$WORKERID #redundant - see main loop
#echo created file $ME.$F1$WORKERID >> $DBG
plot $COL $ROW "Worker$WORKERID: ACTIVE-TID:$THREADID INIT " good
;;
"update" )
plot $COL $ROW "Worker$WORKERID: ACTIVE-TID:$THREADID AGE:$AGE" warn
;;
"setfree" )
plot $COL $ROW "Worker$WORKERID: FREE " fail
rm /tmp/$ME.$F1$WORKERID
;;
* )
;;
esac
}
getfreeworkerid()
{
for i in $(seq 1 $[$THREADLIMIT+1])
do
if [ ! -e /tmp/$ME.$F1$i ];then
#echo "getfreeworkerid returned $i" >> $DBG
break
fi
done
if [ $i -eq $[$THREADLIMIT+1] ];then
#echo "no free threads" >> $DBG
echo 0
#exit
else
echo $i
fi
}
updateIPC()
{
COMPLETE=$(cat $IPC) #read IPC
COMPLETE=$[$COMPLETE+1] #increment IPC
echo $COMPLETE > $IPC #write back to IPC
}
worker()
{
WORKERID=$1
THREADID=$2
#echo "new worker WORKERID:$WORKERID THREADID:$THREADID" >> $DBG
#accessing common terminal requires critical blocking section
(flock -x -w 10 201
trackthread $WORKERID $THREADID setactive
)201>/tmp/$ME.lock
let "RND = $RANDOM % $MAXTHREADDUR +1"
for s in $(seq 1 $RND) #simulate random lifespan
do
sleep 1;
(flock -x -w 10 201
trackthread $WORKERID $THREADID update $s
)201>/tmp/$ME.lock
done
(flock -x -w 10 201
trackthread $WORKERID $THREADID setfree
)201>/tmp/$ME.lock
(flock -x -w 10 201
updateIPC
)201>/tmp/$ME.lock
}
threadcount()
{
TC=$(ls /tmp/$ME.$F1* 2> /dev/null | wc -l)
#echo threadcount is $TC >> $DBG
THREADCOUNT=$TC
echo $TC
}
status()
{
#summary status line
COMPLETE=$(cat $IPC)
plot 1 $[$THREADLIMIT+2] "WORKERS $(threadcount)/$THREADLIMIT SPAWNED $SPAWNED/$SPAWN COMPLETE $COMPLETE/$SPAWN SF=$SPEEDFACTOR TIMING=$TPS"
echo -en '\033[K' #clear to end of line
}
function main()
{
while [ $SPAWNED -lt $SPAWN ]
do
while [ $(threadcount) -lt $THREADLIMIT ] && [ $SPAWNED -lt $SPAWN ]
do
WID=$(getfreeworkerid)
worker $WID $SPAWNED &
touch /tmp/$ME.$F1$WID #if this loops faster than file creation in the worker thread it steps on itself, thread tracking is best in main loop
SPAWNED=$[$SPAWNED+1]
(flock -x -w 10 201
status
)201>/tmp/$ME.lock
sleep $TPS
if ((! $[$SPAWNED%100]));then
#rethink thread timing every 100 threads
threadspeed
fi
done
sleep $TPS
done
while [ "$(threadcount)" -gt 0 ]
do
(flock -x -w 10 201
status
)201>/tmp/$ME.lock
sleep 1;
done
status
}
clear
threadspeed
main
wait
status
echo
Senaryonuz şöyle görünmelidir:
prog1 &
prog2 &
.
.
progn &
wait
progn+1 &
progn+2 &
.
.
Sisteminizin bir seferde n iş alabileceğini varsayarsak. bir seferde yalnızca n iş çalıştırmak için wait kullanın.
İle bashj ( https://sourceforge.net/projects/bashj/ ) kullanarak, sadece birden çalıştırmak mümkün olmalıdır süreçleri (yön diğerleri önerilen) değil, aynı zamanda birden fazla konu Betiğiniz kontrollü bir JVM. Ama elbette bu bir java JDK gerektirir. İş parçacıkları süreçlerden daha az kaynak tüketir.
İşte çalışan bir kod:
#!/usr/bin/bashj
#!java
public static int cnt=0;
private static void loop() {u.p("java says cnt= "+(cnt++));u.sleep(1.0);}
public static void startThread()
{(new Thread(() -> {while (true) {loop();}})).start();}
#!bashj
j.startThread()
while [ j.cnt -lt 4 ]
do
echo "bash views cnt=" j.cnt
sleep 0.5
done
wait
! Evet, bashta komut dosyasının alt süreçlerini bekleyebilirsiniz.