Borulu komutları paralel olarak yürütme


16

Aşağıdaki senaryoyu düşünün. Program A ve B iki programım var. Bu iki programı kullanmanın yolu elbette:

foo @ bar: ~ $ A | B

Şimdi bunun sadece bir çekirdek yediğini fark ettim; bu yüzden merak ediyorum:

A ve B programları aynı hesaplama kaynaklarını paylaşıyor mu? Eğer öyleyse, A ve B'yi aynı anda çalıştırmanın bir yolu var mı?

Fark ettiğim başka bir şey, A'nın B'den çok daha hızlı çalıştığıdır, bu yüzden bir şekilde daha fazla B programı çalıştırabilir mi ve A'nın paralel olarak çıkardığı çizgileri işlemesine izin verebilir miyim diye merak ediyorum.

Yani, A satırlarını çıkarır ve bu satırları okuyan (ilk önce onları okuyan) N programının B örneğini işler ve bunları stdout'ta çıkarır.

Son sorum şu:

Potansiyel olarak ortaya çıkabilecek yarış koşullarına ve diğer tutarsızlıklara bakmak zorunda kalmadan birkaç B işlemi arasında çıktıyı A'ya bağlamanın bir yolu var mı?


1
A | B | CAyrı işlemlerde olduğu gibi paralel olsa da, boruların doğası nedeniyle (B, A'nın çıkışını beklemek zorundadır, C, B'nin çıkışını beklemek zorundadır), bazı durumlarda hala doğrusal olabilir. Tamamen ne tür çıktılar ürettiklerine bağlıdır. Çoklu çalışmanın çok Byardımcı olacağı pek çok durum yoktur, wcbölme normal olarak saymaktan daha fazla kaynak alabileceğinden , paralel wc örneğinin normalden daha yavaş olması tamamen mümkündür . Dikkatli kullanın.
frostschutz

Yanıtlar:


14

Bir sorun split --filter, çıktının karıştırılabilmesidir, böylece işlem 1'den yarım çizgi ve ardından işlem 2'den yarım çizgi alırsınız.

GNU Parallel, karışıklık olmayacağını garanti eder.

Yapmak istediğinizi varsayalım:

 A | B | C

Ama bu B çok yavaş ve bu yüzden bunu paralelleştirmek istiyorsunuz. Sonra şunları yapabilirsiniz:

A | parallel --pipe B | C

GNU Paralel olarak \ n ve varsayılan olarak 1 MB boyutunda böler. Bu --recend ve --block ile ayarlanabilir.

GNU Parallel hakkında daha fazla bilgiyi şu adreste bulabilirsiniz: http://www.gnu.org/s/parallel/

GNU Paralel'i aşağıdakilerle sadece 10 saniyede kurabilirsiniz:

wget -O - pi.dk/3 | sh 

Giriş videosunu http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 adresinde izleyin.


1
Kurulum yöntemine kesinlikle katılmıyorum :-), +1 çünkü çözümünüz benimki ile ilgili sorunların çoğunu çözüyor.
LSerni

Bu gerçekten güzel. Kullanılacak parametreler için herhangi bir öneriniz var mı? Program A'nın dakikada yaklaşık 5 GB'den fazla 1 TB'tan fazla veri üreteceğini biliyorum. B programı verileri A'nın çıkışından 5 kat daha yavaş işler ve bu görev için elimde 5 çekirdek var.
Jernej

GNU Parallel şu anda en fazla 100 MB / sn işleyebilir, bu nedenle bu sınıra dokunacaksınız. Optimal --block-size, RAM miktarına ve yeni bir hıza ne kadar hızlı başlayabileceğinize bağlı olacaktır B. Sizin durumunuzda bunu --block 100Mnasıl yapacağımı görüyorum.
Ole Tange

@lserni Çoğu UNIX makinesinde çalışan ve kullanıcıdan benzer miktarda çalışma gerektiren daha iyi bir yükleme yöntemi bulabilir misiniz?
Ole Tange

4
Üzgünüm, kendimi açıklığa kavuşturmadım. Yükleme yöntemi - geçirilen komut dosyası sh- harika. Sorun sh'ye geçirilmesinde yatıyor: bir siteden yürütülebilir kod indirme ve çalıştırma . Unutmayın, belki de çok paranoyak oluyorum, çünkü ısmarlama bir RPM veya DEB'nin temelde aynı şey olduğuna itiraz edebilir ve kodun kopyalanıp yapıştırılacak bir sayfaya gönderilmesi bile insanların körü körüne yapmasına neden olur neyse.
LSerni

13

Eğer yazarken A | B, her iki işlem zaten paralel olarak çalıştırılır. Onları yalnızca tek bir çekirdek olarak görüyorsanız, bunun nedeni büyük olasılıkla CPU benzeşimi ayarlarından (belki de farklı bir benzeşime sahip bir işlem oluşturmak için bazı araçlar vardır) veya bir işlemin tüm çekirdeği tutmak için yeterli olmaması ve sistemin " hesaplamayı yaymamayı tercih ediyor.

Bir B ile birkaç B çalıştırmak için split, aşağıdaki --filterseçenek gibi bir araca ihtiyacınız vardır :

A | split [OPTIONS] --filter="B"

Ancak bu, çıktılardaki satırların sırasını bozmakla yükümlüdür, çünkü B işleri aynı hızda çalışmaz. Bu bir sorunsa, B i-th çıkışını bir ara dosyaya yönlendirmeniz ve sonunda kullanarak birleştirmeniz gerekebilir cat. Bu da, kayda değer bir disk alanı gerektirebilir.

Diğer seçenekler mevcut (B bütün "yuvarlak" bittikten bir, bir eşdeğer bitene kadar beklemek mesela tek bir satır tamponlu çıkışına B her örneğini sınırlayabilir, azaltmak için split'ın harita ve catgeçici çıkışı birlikte), değişen verimlilik seviyeleri ile. Az önce açıklanan 'yuvarlak' seçeneği B'nin en yavaş örneğinin bitmesini bekleyecek , bu nedenle B için mevcut ara belleğe alma işlemine büyük ölçüde bağlı olacaktır; [m]bufferişlemlerin ne olduğuna bağlı olarak yardımcı olabilir veya olmayabilir.

Örnekler

İlk 1000 sayıyı oluşturun ve çizgileri paralel olarak sayın:

seq 1 1000 | split -n r/10 -u --filter="wc -l"
100
100
100
100
100
100
100
100
100
100

Çizgileri "işaretleyecek olsaydık, her birinci satırın # 1 işlemine, her beşinci satırın da # 5 işlemine gönderildiğini görürdük. Dahası, splitikinci süreci doğurma zamanında , birincisi kotasına zaten iyi bir yoldur:

seq 1 1000 | split -n r/10 -u --filter="sed -e 's/^/$RANDOM - /g'" | head -n 10
19190 - 1
19190 - 11
19190 - 21
19190 - 31
19190 - 41
19190 - 51
19190 - 61
19190 - 71
19190 - 81

Zaman, bir 2-çekirdekli makinesi üzerinde çalışan seq, splitve wcişlemler çekirdekler paylaşır; ancak daha yakından bakarsak, sistem ilk iki işlemi CPU0'da bırakır ve CPU1'i çalışan işlemler arasında böler:

%Cpu0  : 47.2 us, 13.7 sy,  0.0 ni, 38.1 id,  1.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 15.8 us, 82.9 sy,  0.0 ni,  1.0 id,  0.0 wa,  0.3 hi,  0.0 si,  0.0 st
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
 5314 lserni    20   0  4516  568  476 R 23.9  0.0   0:03.30 seq
 5315 lserni    20   0  4580  720  608 R 52.5  0.0   0:07.32 split
 5317 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5318 lserni    20   0  4520  572  484 S 14.0  0.0   0:01.88 wc
 5319 lserni    20   0  4520  576  484 S 13.6  0.0   0:01.88 wc
 5320 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.85 wc
 5321 lserni    20   0  4520  572  484 S 13.3  0.0   0:01.84 wc
 5322 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5323 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5324 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.87 wc

Özellikle splitönemli miktarda CPU yediklerine dikkat edin . Bu A'nın ihtiyaçları ile orantılı olarak azalacaktır; yani A, daha ağır bir işlemse seq, göreli yükü splitazalacaktır. Ama (böylece hiçbir gerektiğini fazla 2-3 B A ile birlikte tutmak için) bir çok hafif bir süreçtir ve B oldukça hızlıdır, o zaman birlikte koşutlama split(ya da genel olarak borular) olabilir değer bu olamaz.


Ubuntu'da bulunan bölünmenin --filter seçeneği olmaması ilginçtir. Bunun için ne tür bir işletim sistemi kullanılıyor?
Jernej

Linux OpenSuSE 12.3, coreutils ile ( gnu.org/software/coreutils/manual/html_node/… ). Bir Ubuntu'yu ele geçirmeye çalışacağım, benzer şekilde adlandırılmış bir aracı barındırmak için adı değiştirmiş olabilirler.
LSerni

split --filterSeçenek eksik olduğundan emin misiniz ? Ubuntu 12.04-LTS'de ("wheezy / sid"), orada ve örneklerim işe yarıyor. splitGNU coreutils'den farklı bir kurulum yapabilir misiniz ?
LSerni

Bunun için teşekkürler. Daha yeni bir Coreutils sürümü kurmak zorunda kaldım. BTW, eğer A programını tek başına çalıştırırsam, A | B sonra birlikte bütün bir çekirdeği yerler, A sürecini% 15 yiyor ve B sürecini% 85 yiyorlar. Bunun neden böyle olduğunu anlıyor musunuz?
Jernej

2
Bu muhtemelen engelleme nedeniyle . B, A'dan daha ağırsa, A çıkışını gönderemez ve yavaşlar. Başka bir olasılık, çalışması sırasında A'nın B'ye vermesidir (örneğin disk / net). Farklı bir sistemde B CPU1'in% 100'üne ve A'ya CPU0'ın% 18'ine atandığını görebilirsiniz. Tek bir çekirdeği doyurmak için tek bir A örneği almak için muhtemelen 85/15 ~ 5.67 = 5 ila 6 arasında B örneğine ihtiyacınız vardır. G / Ç, varsa, bu değerleri kırabilir.
LSerni
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.