Paralel olarak üretilen diğer üç akıştan tek bir çıkış akışı oluşturma


10

Farklı formatlarda üç çeşit veri var; her veri türü için, onu tek bir birleşik formata dönüştüren bir Python betiği vardır.

Bu Python betiği yavaş ve CPU'ya bağlı (çok çekirdekli bir makinede tek bir çekirdeğe), bu yüzden üç örneğini - her veri türü için bir tane - çalıştırmak ve çıktılarını içine geçirmek için birleştirmek istiyorum sort. Temel olarak, buna eşdeğer:

{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n

Ama üç script paralel olarak çalışıyor.

GNU'nun akışı işleyen bir betiğin n örneği arasında bazı stdout akışını yuvarlamak için kullanıldığı bu soruyu buldum split.

Bölünmüş adam sayfasından:

-n, --number=CHUNKS
          generate CHUNKS output files.  See below
CHUNKS  may be:
 N       split into N files based on size of input
 K/N     output Kth of N to stdout
 l/N     split into N files without splitting lines
 l/K/N   output Kth of N to stdout without splitting lines
 r/N     like 'l'  but  use  round  robin  distributio

Yani r/Nkomut " satırları bölmeden " anlamına gelir .

Buna dayanarak, aşağıdaki çözümün mümkün olduğu anlaşılıyor:

split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF

choose_scriptBu nerede :

#!/bin/bash
{ read x; ./handle_$x.py; }

Ne yazık ki, bazı kesişen çizgiler ve orada olmaması gereken birçok yeni çizgi görüyorum.

Örneğin, Python betiklerimi bunu yapan bazı basit bash betikleriyle değiştirirsem:

#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;

.

#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;

.

#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;

Bu çıktıyı görüyorum:

1-8394

2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981

Bu sinir bozucu - yukarıda yapıştırdığım man sayfası özetine dayanarak, satır bütünlüğünü korumalıdır.

Açıkçası, -uargümanı kaldırırsam çalışır , ancak daha sonra arabelleğe alınır ve komut dosyalarından biri dışındaki her şeyin çıktısını tamponladığı için belleğim tükenir.

Burada bir fikir varsa, çok takdir edilecektir. Burada derinliğimden uzaktayım.


Freenode üzerinde #bash'deki bazı insanlar, üç süreci de ortaya çıkardığımı ve arka planlarını oluşturduğumu, özel FD'lere yazdığımı, daha sonra bu FD'leri döngülediğini ve onlar için satırları okuduğumu, ancak bunu nasıl uygulanabilir hale getirebileceğimi önermedi. Nasıl yapıldığını coprocgerçekten görmeme rağmen, bash içindeki yerleşime bakmam da söylendi .
Cera

1
Bunu ara dosyalar olmadan yapmak zorunda mısınız? Sadece yapamaz job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3mısın?
angus

Yanıtlar:


2

GNU paralelinin -u seçeneğini kullanmayı deneyin.

echo "1\n2\n3" | parallel -u -IX ./handle_X.sh

Bu, onları herhangi bir işlemin tamamını arabelleğe almadan, paralel olarak çalıştırır.


Ben karıştı biraz kafam - olduğu Xiçinde IXsöylüyorum -Iki X değiştirilmesi için bayrak olacak, ya da uyguluyor -Xgörünüşte de alakalı bir anlama sahiptir bayrağı?
Cera

Hıh. Bunu yapıyorum: parallel -u -X ./handle_{}.sh ::: "1" "2" "3"ve ne yazık ki hala bazı çıktı mangling görüyorum.
Cera

birincisi: kullanabilirsiniz parallel -u ./handle_{}.sh, ancak değiştirmeyi tercih ederim, çünkü parantezler de komutlara katılma anlamına gelir (sorunuzda olduğu gibi).
flowblok

Benim için çalışıyor gibi görünüyor, grepim herhangi bir karışıklık almıyor : pastie.org/5113187 (test bash komut dosyalarını mı, yoksa gerçek Python komut dosyalarınızı mı kullanıyorsunuz?)
12:49

Sorun şu ki, aslında paralel bir şey yapmıyor. Bash komut dosyalarını kullanıyorum - pastie.org/5113225
Cera

2

Deneyin:

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py

handle_1.pyBir dosya adı alırsa :

parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

Çıktının karışık olmasını istemezsiniz, bu nedenle -u kullanmayın.

Siparişi korumak istiyorsanız (böylece tüm handle_1 çıktısı handle_2'den önce olur ve böylece sıralamayı önleyebilirsiniz):

parallel -k  ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*

Hala sıralanmasını istiyorsanız, sıralamayı paralel hale getirebilir ve kullanabilirsiniz sort -m:

parallel --files "./handle_{1}.py {2} | sort -n"  ::: 1 2 3 ::: files* | parallel -j1 -X sort -m

$ TMPDIR çıktıyı tutacak kadar büyük bir dirse ayarlayın.


1
Çıktı 'karışık' istiyorum - Sadece son çıktıdaki her satırın alt işlemlerden birinden tek bir satır olduğundan emin olmak istiyorum. Karıştırmazsam, sistem henüz yazdırılmamış olan stdout akışlarını arabelleğe alır.
Cera

GNU Parallel ile belleğiniz tükenmez: Bellekte arabellek oluşturmaz. Neden hafızada tampon olduğunu düşünüyorsun?
Ole Tange

2

Belki bir şey eksik, ama yapamazsın:

(./handle_1.py & ./handle_2.py & ./handle_3.py) | sort -n

Her işlemden satırların serpiştirilmemesini istiyorsanız, işlemin kendilerinin tamamen yazdığından emin olmak ve muhtemelen writebir boruya s olarak çıktı arabelleğini devre dışı bırakmak , daha büyük olmadıkları sürece atomik olacağı garanti edilir. PIPE_BUF. Örneğin, emin yapabiliriz yapar à la kullanım için tampon stdiove çağrı fflushya da her türlü eşdeğer olduğu pythonbir veya birkaç satır yazılmış sonra.

Python komut dosyalarını değiştiremiyorsanız şunları yapabilirsiniz:

lb() { grep --line-buffered '^'; }

(GNU grep ile) veya:

lb() while IFS= read -r l; do printf '%s\n' "$l"; done

(Komutların çıktısı metin değilse aşağıdaki açıklamalardaki notlara bakın)

Ve yapın:

(./handle_1.py | lb & ./handle_2.py | lb & ./handle_3.py | lb) | sort -n

Bu 3 lbişlemden kaçınmak için başka bir seçenek, bir komuttan üç çıkışa sahip olmak select/ bir pollçıkışın nereden geldiğini görmek ve sortsatır tabanlı beslemek , ancak biraz programlama gerektirir.


waitOrada bir tane lazım , sanırım.
derobert

1
Hayır, bazı programlar çıkmadan önce stdout'larını kapatmadıkça, çünkü boru ve sort -nüzerinde fd açık olan tüm programlar çıkana kadar kalacaktır.
Stéphane Chazelas

Gerçekten, test ettim, haklısın.
derobert

Hayır, hala karışık çıktı alıyorum. Çizgiler birbirine karışır ve serpiştirilir.
Cera

1
OK @Cerales, güncellenmiş cevabımı gör
Stéphane Chazelas

1

Flowbok'un cevabı doğru çözümdü. Garip bir şekilde, GNU'nun parallelçıktısı doğrudan bir dosyaya çıktıysa karıştırılır - ancak bir tty'ye giderse değil.

Neyse ki, script -cbir tty taklit etmek için kullanılabilir.

Hala üç senaryo var:

#!/bin/bash
# handle_1.sh
while true; do echo "1-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_2.sh
while true; do echo "2-$RANDOM$RANDOM$RANDOM$RANDOM"; done

.

#!/bin/bash
# handle_3.sh
while true; do echo "3-$RANDOM$RANDOM$RANDOM$RANDOM"; done

Sonra paralel çağrıyı kapsülleyen bir dosya var:

#!/bin/bash
# run_parallel.sh
parallel -u -I N ./handle_N.sh ::: "1" "2" "3"

Ve sonra şöyle diyorum:

script -c ./run_parallel > output

Çıktıdaki satırlar, farklı komut dosyalarının çıktısı arasında satır satır karıştırılır, ancak belirli bir satırda karıştırılmaz veya araya girilmez.

Tuhaf davranış parallel- Bir hata raporu verebilirim.

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.