Eşzamanlı sayıda komut sınırına paralel olarak komut çalıştırma


23

Sıralı: for i in {1..1000}; do do_something $i; done- çok yavaş

Paralel: for i in {1..1000}; do do_something $i& done- çok fazla yük

Komutlar paralel olarak nasıl çalıştırılır, ancak örneğin dakikada 20'den fazla değil?

Şimdi genellikle kesmek gibi kullanmak for i in {1..1000}; do do_something $i& sleep 5; done, ama bu iyi bir çözüm değil.

Güncelleme 2 : Kabul edilen cevabı bir betiğe dönüştürdü: http://vi-server.org/vi/parallel

#!/bin/bash

NUM=$1; shift

if [ -z "$NUM" ]; then
    echo "Usage: parallel <number_of_tasks> command"
    echo "    Sets environment variable i from 1 to number_of_tasks"
    echo "    Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
    echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
    exit 1
fi

export CMD="$@";

true ${MAKEOPTS:="-j20"}

cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})

all: \${jobs}

\${jobs}:
        i=\$@ sh -c "\$\$CMD"
EOF

Çalışması için "i =" işaretinden önce 8 boşluğu 2 sekme ile değiştirmeniz gerektiğini unutmayın.

Yanıtlar:


15

Bunun için GNU Paralel yapılır.

seq 1 1000 | parallel -j20 do_something

Hatta uzak bilgisayarlarda iş bile çalıştırabilir. CPU2 başına 1 iş çalıştıran server2 ve yerel bilgisayarı kullanarak bir MP3'ü OGG'ye yeniden kodlamak için bir örnek:

parallel --trc {.}.ogg -j+0 -S server2,: \
     'mpg321 -w - {} | oggenc -q0 - -o {.}.ogg' ::: *.mp3

GNU Parallel'a giriş videosunu buradan izleyebilirsiniz:

http://www.youtube.com/watch?v=OpaiGYxkSuQ


"Moreutils" hakkında bir şey bilmiyorsunuz ve bu iş için zaten bir araç var. Bakmak ve karşılaştırmak.
Vi.

1
parallelMoreutils GNU Paralel değildir ve oldukça da seçenekleri sınırlıdır. Yukarıdaki komut moreutils komutunun paraleliyle çalışmaz.
Ole Tange

1
Bir daha seçeneği: xargs --max-procs=20.
Vi.

4

Bir bash çözümü değil, ancak muhtemelen -lmaksimum yükü aşmayacak şekilde bir Makefile kullanmalısınız .

NJOBS=1000

.PHONY = jobs
jobs = $(shell echo {1..$(NJOBS)})

all: $(jobs)

$(jobs):
    do_something $@

Sonra bir seferde 20 işe başlamak için

$ make -j20

veya 5 yükü aşmadan mümkün olduğunca fazla işe başlamak

$ make -j -l5

Şimdilik kötü olmayan bir çözüm gibi görünüyor.
Vi.

2
echo -e 'PHONY=jobs\njobs=$(shell echo {1..100000})\n\nall: ${jobs}\n\n${jobs}:\n\t\techo $@; sleep `echo $$RANDOM/6553 | bc -l`' | make -f - -j20Şimdi yine daha acayip görünüyor.
Vi.

@vi: oh my ....
Benjamin Bannier

Çözümünüzü bir betiğe dönüştürdü. Şimdi kolaylıkla kullanılabilir.
Vi.

2

betiği soruya biçimlendirme ile gönderme:

#!/bin/bash

NUM=$1; shift

if [ -z "$NUM" ]; then
    echo "Usage: parallel <number_of_tasks> command"
    echo "    Sets environment variable i from 1 to number_of_tasks"
    echo "    Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
    echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
    exit 1
fi

export CMD="$@";

true ${MAKEOPTS:="-j20"}

cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})

all: \${jobs}

\${jobs}:
        i=\$@ sh -c "\$\$CMD"
EOF

"İ =" öncesinde 8 boşluğu 2 sekme ile değiştirmeniz gerektiğini unutmayın.


1

Basit bir fikir:

İ modulo 20'yi kontrol edin ve do_something'den önce wait shell-komutunu yürütün.


Tüm mevcut görevlerin tamamlanmasını bekleyecek (görevlerin çiziminde sarkmalar yaratacak) veya daha uzun süre durabilecek belirli bir görevi bekleyecek (bu durumda yine sarkmalar yaratacak)
Vi.

@Vi: Kabuk bekleme, bu kabuğa ait tüm arka plan görevleri içindir.
harrymc

1

psKaç işlem yaptığınızı saymak için kullanabilirsiniz ve bu belirli bir eşiğin altına düştüğünde başka bir işleme başlarsınız.

Sahte kod:

i = 1
MAX_PROCESSES=20
NUM_TASKS=1000
do
  get num_processes using ps
  if num_processes < MAX_PROCESSES
    start process $i
    $i = $i + 1
  endif
  sleep 1 # add this to prevent thrashing with ps
until $i > NUM_TASKS

1
for i in {1..1000}; do 
     (echo $i ; sleep `expr $RANDOM % 5` ) &
     while [ `jobs | wc -l` -ge 20 ] ; do 
         sleep 1 
     done
done

Olabilir while [ `jobs | wc -l` -ge 20]; domi?
Vi.

emin, ama benim örnekte, o zaman njobsiki kez hesaplamak zorunda kalacak ve uyku görevlerini çalıştıran kabuk komut dosyalarında performans oldukça önemlidir;)
msw

Yani sürümünüz beklendiği gibi çalışmıyor. Ben değiştirmek sleep 1için sleep 0.1ve biz herhangi bir iş sadece 1 saniye beklemez, bitmiş olur beklemek zorundayız 20'den fazla iş varsa o 40-50 yerine 20'ye ortalama njobs başlar.
Vi.

0

böyle yapabilirsin.

threads=20
tempfifo=$PMS_HOME/$$.fifo

trap "exec 1000>&-;exec 1000<&-;exit 0" 2
mkfifo $tempfifo
exec 1000<>$tempfifo
rm -rf $tempfifo

for ((i=1; i<=$threads; i++))
do
    echo >&1000
done

for ((j=1; j<=1000; j++))
do
    read -u1000
    {
        echo $j
        echo >&1000
    } &
done

wait
echo "done!!!!!!!!!!"

adlandırılmış borular kullanarak, her seferinde, 20 alt kabuğu paralel olarak çalıştırır.

Umarım yardımcı olur :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.