Paralel kabuk döngüleri


11

Birçok dosyayı işlemek istiyorum ve burada bir sürü çekirdek olduğundan paralel olarak yapmak istiyorum:

for i in *.myfiles; do do_something $i `derived_params $i` other_params; done

Makefile çözümünü biliyorum ama komutlarımın kabuk globbing listesinden argümanlara ihtiyacı var. Ne buldum:

> function pwait() {
>     while [ $(jobs -p | wc -l) -ge $1 ]; do
>         sleep 1
>     done
> }
>

Bunu kullanmak için, tek yapılması gereken işler ve bir pwait çağrısından sonra, parametre paralel işlemlerin sayısını verir:

> for i in *; do
>     do_something $i &
>     pwait 10
> done

Ama bu çok iyi çalışmıyor, örneğin ben bir döngü için birçok dosya dönüştürme ama bana hata ve işlerini geri bıraktı denedim.

Zsh posta listesindeki tartışma şimdiye kadar çok eski olduğundan bunun henüz yapılmadığına inanamıyorum. Daha iyisini biliyor musun?


Bu soruya benzer: superuser.com/questions/153630/… Bu tekniğin işinize yarayıp yaramadığına bakın.
JRobert

Hata mesajlarını gönderirseniz yardımcı olur.
sonraki duyuruya kadar duraklatıldı.

@JRobert evet Bunu biliyordum, ancak makefile yaklaşımı dediğim gibi çalışmadığından bu aslında yardımcı olmuyor! @Dennis: Tamam, önce bana belirtilen süreç sayısından daha fazlasını göstermenin yanı sıra bir üst koştum. İkincisi, isteme düzgün bir şekilde dönmez. Üçüncüsü işlerin geri alınmadığını söylediğim doğru değildi: echo "DONE"Aktif işler bitmeden önce yürütülen döngüden sonra bir gösterge yerleştirdim . => Bu bana işlerin bittiğini düşündürdü.
matematik

Yanıtlar:


15

Orada Makefile olan senin soruna iyi bir çözüm. Bu paralel yürütmeyi bir kabukta programlayabilirsiniz, ancak fark ettiğiniz gibi zor. Paralel bir uygulama, sadece işe başlama ve işten çıkarılmalarını tespit etmekle kalmayacak, aynı zamanda zor olan yük dengelemesini de ele alacaktır.

Globbing gereksinimi bir engel değildir: onu destekleyen uygulamalar vardır. Joker karakter genişletmesi $(wildcard *.c)ve kabuk erişimi gibi $(shell mycommand)GNU markası (GNU'daki arama işlevleri daha fazla bilgi için kılavuzu oluşturur). makeLinux'ta varsayılan değerdir ve diğer birçok sistemde kullanılabilir. İşte ihtiyaçlarınıza göre ayarlayabileceğiniz bir Makefile iskeleti:

sources = $ (joker karakter * .src)

all: $ (kaynaklar: .src = .tgt)

% .tgt: $ .src
    do_something $ <$$ (türetilmiş_params $ <)> $ @

make -j4Dört işi paralel olarak yürütmek veya make -j -l3yük ortalamasını 3 civarında tutmak gibi bir şey çalıştırın .


8

Türetilmiş argümanlarınızın neye benzediğinden emin değilim. Ancak GNU Parallel http: // www.gnu.org/software/parallel/ ile bunu cpu çekirdeği başına bir iş çalıştırmak için yapabilirsiniz:

find . | parallel -j+0 'a={}; name=${a##*/}; upper=$(echo "$name" | tr "[:lower:]" "[:upper:]");
   echo "$name - $upper"'

Türetmek istediğiniz şey yalnızca .extension değerini değiştiriyorsa, {.} Kullanışlı olabilir:

parallel -j+0 lame {} -o {.}.mp3 ::: *.wav

Http://www.youtube.com/watch?v=OpaiGYxkSuQ adresinden GNU Paralel'e giriş videosunu izleyin


7

Kabuğun waitkomutunu kullanmak sizin için uygun olmaz mı?

for i in *
do
    do_something $i &
done
wait

Döngünüz bir işi yürütür, sonra bekler, sonra bir sonraki işi yapar. Yukarıdaki işi sizin için değilse taşımak, sonra seninki daha işe yarayabilecek pwaitsonra done.


hayır 1 milyon dosyayla 1 milyon işlemim olur mu yoksa yanılıyor muyum?
matematik

1
@brubelsabs: Evet, bu olur denemek milyon süreçleri yapmak. Sorunuzda kaç dosyayı işlemeniz gerektiğini söylemediniz. Bunu forsınırlamak için iç içe döngüler kullanmanız gerektiğini düşünürüm : for file in *; do for i in {1..10}; do do_something "$i" & done; wait; done(denenmemiş) Her seferinde on tane yapmalı ve sonraki ona başlamadan önce her grubun onunun tamamlanmasını beklemelisiniz. &Döngünüz her seferinde bir tane yapar . Diğer seçenekler için JRobert'in bağlandığı soruya bakın . Sizinkine (ve buna) benzer diğer soruları Stack Stack Overflow'da arayın.
sonraki duyuruya kadar duraklatıldı.

Eğer OP bir milyon dosya öngörürse, onunla bir sorunu olurdu for i in *. Bir boru veya başka bir şeyle döngüye argümanlar iletmesi gerekecekti. Daha sonra dahili bir döngü yerine, artan bir sayaç çalıştırabilir ve "micro-"wait"-s"her "$ ((i% 32))" -eq '0'

@DennisWilliamson: waitbir iç sayaç döngüsü ile birleştirmek benim için iyi çalıştı. Teşekkürler!
Joel Purra

3

Neden kimse henüz xargs'tan bahsetmedi?

Tam olarak üç argümanınız olduğunu varsayarsak,

for i in *.myfiles; do echo -n $i `derived_params $i` other_params; done | xargs -n 3 -P $PROCS do_something

Aksi takdirde bir sınırlayıcı kullanın (null bunun için kullanışlıdır):

for i in *.myfiles; do echo -n $i `derived_params $i` other_params; echo -ne "\0"; done | xargs -0 -n 1 -P $PROCS do_something

EDIT: yukarıdakiler için, her parametre boş bir karakterle ayrılmalı ve sonra parametre sayısı xargs -n ile belirtilmelidir.


Evet, projemizde birisi aynı fikre sahipti ve MSys ile Windows altında bile harika çalışıyor.
matematik

0

Bazı cevapları denedim. Senaryoyu gerekenden biraz daha karmaşık hale getiriyorlar. İdeal olarak kullanmak parallelveya xargstercih edilirse de, for döngüsü içindeki işlemler karmaşıksa, paralel sağlamak için büyük ve uzun satır dosyaları oluşturmak sorunlu olabilir. bunun yerine kaynağı aşağıdaki gibi kullanabiliriz

# Create a test file 
$ cat test.txt
task_test 1
task_test 2

# Create a shell source file 
$ cat task.sh
task_test()
{
    echo $1
}

# use the source under bash -c 
$ cat test.txt | xargs -n1 -I{} bash -c 'source task.sh; {}'
1
2

Böylece probleminiz için çözüm şöyle görünecektir

for i in *.myfiles; echo " do_something $i `derived_params $i` other_params
" >> commands.txt ; done

tanımlamak do_something.sh

do_something(){
process $1
echo $2 
whatever $3 

}

xargveya ile yürütgnu parallel

   cat commands.txt | xargs -n1 -I{} -P8 bash -c 'source do_something.sh; {}'

İçin yinelemelerin işlevsel bağımsızlığının ima edildiğini varsayıyorum.

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.