Paralel olarak dört görev… bunu nasıl yaparım?


23

Bir dizinde bir sürü PNG resmi var. Bu görüntüleri sıkıştırmak için kullandığım pngout adlı bir uygulamam var. Bu uygulama yaptığım bir komut dosyası tarafından denir. Sorun şu ki, bu komut dosyası bir seferde bir tane yapıyor, şunun gibi:

FILES=(./*.png)
for f in  "${FILES[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 $f R${f/\.\//}
done

Bir seferde sadece bir dosyayı işlemek çok zaman alır. Bu uygulamayı çalıştırdıktan sonra, CPU'nun sadece% 10 olduğunu görüyorum. Bu yüzden bu dosyaları 4 gruba ayırabilirim, her bir dizini bir dizine koyup 4'ü dört terminal penceresinden, dört işlemden geçirebildiğimi keşfettim. iş zamanın 1 / 4'ünü alır.

İkinci sorun, görüntüleri ve grupları bölüp senaryoyu dört dizine kopyalamak, 4 terminal penceresi açmak, bla bla ...

Hiçbir şeyi bölmek zorunda kalmadan tek bir senaryo ile bunu nasıl yaparsınız?

İki şeyi kastediyorum: ilk önce bir bash betiğinden nasıl bir süreci arka plana çekebilirim? (yalnızca sonuna & sonuna ekleyin?) İkincisi: Dördüncü görevleri gönderdikten sonra arka plana görev göndermeyi nasıl durdurabilirim ve komut dosyasını görevler bitinceye kadar beklemeye nasıl koyabilirim? Demek istediğim, arka plana bir görev sona erdiğinde yeni bir görev göndermek, her zaman 4 görevi paralel tutmak mı demek istiyorsunuz? Bunu yapmazsam, döngü zilyonlarca görevi arka plana fırlatacak ve CPU tıkayacaktır.


Yanıtlar:


33

xargsParalel yürütmeyi destekleyen bir kopyasına -Psahipseniz,

printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}

Diğer fikirler için, Wooledge Bash wiki, İşlem Yönetimi makalesinde tam olarak ne istediğinizi anlatan bir bölüme sahiptir .


2
Bu durum için tasarlanmış "gnu paralel" ve "xjobs" da vardır. Çoğunlukla tercih ettiğiniz bir lezzet meselesidir.
12'de

Önerilen komutu açıklar mısınız? Teşekkürler!
Eugene S

1
@EugeneS Hangi kısım hakkında biraz daha net olabilir misiniz? Printf tüm png dosyalarını toplar ve bunları bir boru aracılığıyla xargs'e geçirir, bu da standart girdiden argümanları toplar pngoutve OP'nin çalıştırmak istediği komut için argümanlara birleştirir . Anahtar seçenek, -P 4xargs'a 4 eşzamanlı komut kullanmasını söyler.
jw013

2
Kesin olmadığım için üzgünüm. Neden printfburada sadece normal yerine işlevini kullandınız ls .. | grep .. *.png? Ayrıca xargskullandığınız parametrelerle de ilgileniyordum ( -0ve -I{}). Teşekkürler!
Eugene S

3
@EugeneS Maksimum doğruluk ve sağlamlık için. Dosya adları satır değildir ve lsdosya adlarını kolay ve güvenli bir şekilde ayrıştırmak için kullanılamaz . Sadece güvenli karakterler isimler sınırlandırmaktadır dosyaya kullanmak \0ve /dahil olmak üzere diğer karakteri beri, \ndosya adının kendisinin bir parçası olabilir. printfKullanımları \0sınırlandırmaktadır dosya adlarına ve -0bilgi verir xargsbu. -I{}Söyler xargsyerine {}argüman ile.
jw013

8

Önceden önerilmiş olan çözümlere ek olarak, sıkıştırılmamış bir dosyayı sıkıştırılmamış hale getirmeyi ve make -j 4paralel olarak 4 işi çalıştırmak için kullanmayı açıklayan bir makefile oluşturabilirsiniz . Sorun, sıkıştırılmış ve sıkıştırılmamış dosyaları farklı şekilde adlandırmanız veya farklı dizinlerde saklamanız gerekecek, aksi takdirde makul bir makyaj kuralı yazmak imkansız olacaktır.



5

İki sorunuzu cevaplamak için:

  • evet, satırın sonuna & sonuna eklenmesi, size bir kabuk arkaplan işlemi başlatmanızı söyleyecektir.
  • waitkomutunu kullanarak, daha fazla ilerlemeden önce kabuktan arka plandaki tüm işlemlerin bitmesini beklemesini isteyebilirsiniz.

İşte komut dosyası değiştirildi, böylece jarka plan işlemlerinin sayısını takip etmek için kullanıldı. Ne zaman NB_CONCURRENT_PROCESSESulaşıldığında, senaryo sıfırlanır j0 ve 's yürütme sürdürmeden önce tüm bitirmek için arka plan işlemlerini bekleyin.

files=(./*.png)
nb_concurrent_processes=4
j=0
for f in "${files[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 "$f" R"${f/\.\//}" &
        ((++j == nb_concurrent_processes)) && { j=0; wait; }
done

1
Bu, dört eşzamanlı işlemin sonuncusunu bekleyecek ve daha sonra başka bir dörtlü başlayacaktır. Belki bir tane dört PID dizisi oluşturup daha sonra bu özel PID'leri beklemeli mi?
Nils

Sadece koddaki düzeltmelerimi açıklamak için: (1) Bir stil olarak, büyük harf değişken adlarından, iç kabuk değişkenleriyle potansiyel olarak çakışmalarından kaçının. (2) $fVb için alıntı eklendi (3) [POSIX uyumlu komut dosyaları için kullanın , ancak yalnızca bas [[için her zaman tercih edilir. Bu durumda, ((aritmetik için daha uygundur.
jw013 31.03.2012
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.