समानांतर में उत्पादित तीन अन्य धाराओं में से एक एकल आउटपुट स्ट्रीम बनाना


10

मेरे पास तीन प्रकार के डेटा हैं जो विभिन्न स्वरूपों में हैं; प्रत्येक डेटा प्रकार के लिए, एक पायथन स्क्रिप्ट है जो इसे एकल एकीकृत प्रारूप में बदल देती है।

यह पायथन लिपि धीमी और सीपीयू-बाउंड (मल्टी-कोर मशीन पर सिंगल कोर के लिए) है, इसलिए मैं इसके तीन उदाहरणों को चलाना चाहता हूं - प्रत्येक डेटा प्रकार के लिए एक - और इसे पास करने के लिए उनके आउटपुट को मिलाएं sort। मूल रूप से, इसके बराबर:

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

लेकिन समानांतर में चलने वाली तीन लिपियों के साथ।

मुझे यह प्रश्न मिला कि जीएनयू splitका उपयोग स्क्रिप्ट के n उदाहरणों के बीच कुछ स्टडआउट स्ट्रीम को राउंड-रॉबिन करने के लिए किया जा रहा था जो स्ट्रीम को संभालता है।

विभाजित मैन पेज से:

-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

तो r/Nकमांड का अर्थ है " बिना विभाजन लाइनों के "।

इसके आधार पर, ऐसा लगता है कि निम्नलिखित समाधान संभव होना चाहिए:

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

यह कहाँ choose_scriptहोता है:

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

दुर्भाग्य से, मैं लाइनों के कुछ परस्पर क्रिया को देखता हूं - और बहुत सी नई कहानियां जो वहां नहीं होनी चाहिए।

उदाहरण के लिए, यदि मैं अपनी पायथन लिपियों को कुछ सरल बैश लिपियों से बदलूं जो ऐसा करती हैं:

#!/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;

मैं यह आउटपुट देखता हूं:

1-8394

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

यह कष्टप्रद है - ऊपर दिए गए मैन पेज एक्सट्रेक्ट के आधार पर, इसे लाइन की अखंडता बनाए रखना चाहिए।

जाहिर है कि यह काम करता है अगर मैं -uतर्क को हटा देता हूं , लेकिन फिर यह बफ़र हो गया है और मैं मेमोरी से बाहर चला जाऊंगा क्योंकि यह सभी स्क्रिप्ट्स के आउटपुट को बफ़र करता है।

अगर किसी को यहाँ कुछ अंतर्दृष्टि है यह बहुत सराहना की जाएगी। मैं यहाँ अपनी गहराई से बाहर हूँ।


Freenode के #bash में कुछ लोगों ने सुझाव दिया कि मैं सभी तीन प्रक्रियाओं को अपनाता हूं और उन्हें पृष्ठभूमि देता हूं, कस्टम FD को लिखता हूं, फिर उन FD पर लूप करता हूं और उनके लिए लाइनें पढ़ता हूं, लेकिन मुझे यह पता नहीं चला है कि कैसे वह काम करने योग्य है। मुझे यह भी कहा गया coprocकि मैं बैश में बिलिन को देखता हूं, हालांकि मैं वास्तव में नहीं देखता कि यह कैसे लागू होता है।
सेरा

1
क्या आपको इसे मध्यवर्ती फ़ाइलों के बिना करना है? क्या आप बस नहीं कर सकते थे job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3?
कोण

जवाबों:


2

जीएनयू समानांतर के -u विकल्प का उपयोग करने का प्रयास करें।

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

यह किसी भी प्रक्रिया की संपूर्णता को बफर किए बिना, उन्हें समानांतर में चलाता है।


मैं एक छोटे से उलझन में हूँ - है Xमें IXबता रहा -Iहै कि एक्स की जगह के लिए झंडा होगा, या यह आवेदन कर रहा है -Xझंडा है, जो उचित रूप में भी एक प्रासंगिक अर्थ नहीं है?
सेरा

Hmph। मैं यह कर रहा हूं: parallel -u -X ./handle_{}.sh ::: "1" "2" "3"और दुर्भाग्य से मैं अभी भी कुछ आउटपुट मैनबलिंग देख रहा हूं।
सेरा

पूर्व: आप भी उपयोग कर सकते हैं parallel -u ./handle_{}.sh, लेकिन मैं इसे बदलना पसंद करता हूं, क्योंकि ब्रेसिज़ को एक साथ कमांड में शामिल होने का अर्थ भी है (जैसा कि आपके प्रश्न में)।
प्रवाह

मेरे लिए काम करने लगता है, मेरा grep किसी भी प्रकार की छेड़छाड़ नहीं करता है: pastie.org/5113187 (क्या आप टेस्ट बैश स्क्रिप्ट का उपयोग कर रहे हैं, या आपकी वास्तविक पायथन स्क्रिप्ट?)
flowblok

समस्या यह है कि यह वास्तव में समानांतर में कुछ भी नहीं कर रहा है। मैं बैश स्क्रिप्ट्स का उपयोग कर रहा हूं - pastie.org/5113225
Cera

2

प्रयत्न:

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

यदि handle_1.pyकोई फ़ाइल नाम लेता है:

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

आप आउटपुट को मिश्रित नहीं करना चाहते हैं, इसलिए -u का उपयोग न करें।

यदि आप ऑर्डर रखना चाहते हैं (तो सभी हैंडल_1 आउटपुट handle_2 से पहले हैं और इस प्रकार आप छँटाई से बच सकते हैं):

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

यदि आप अभी भी इसे क्रमबद्ध करना चाहते हैं, तो आप सॉर्ट और उपयोग को समानांतर कर सकते हैं sort -m:

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

$ TMPDIR को एक dir में सेट करें जो आउटपुट को रखने के लिए पर्याप्त है।


1
मैं आउटपुट 'मिश्रित' चाहता हूं - मैं सिर्फ यह सुनिश्चित करना चाहता हूं कि अंतिम आउटपुट में हर लाइन सबप्रोसेस में से एक से एक लाइन हो। अगर मैं इसे नहीं मिलाता हूं, तो सिस्टम मेमोरी से बाहर चलेगा, जो अभी तक प्रिंट नहीं हो रही स्टडआउट स्ट्रीम को बफ़र कर रहा है।
सेरा

जीएनयू समानांतर के साथ आप मेमोरी से बाहर नहीं निकलेंगे: यह मेमोरी में बफर नहीं करता है। आप इसे स्मृति में बफ़र क्यों मानते हैं?
ओले तांगे

2

शायद मुझे कुछ याद आ रहा है, लेकिन क्या आप ऐसा नहीं कर सकते:

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

यदि आप चाहते हैं कि प्रत्येक प्रक्रिया से लाइनें परस्पर न हों, तो यह आसान है कि यह सुनिश्चित किया जाए कि प्रक्रिया स्वयं उन्हें पूरी तरह से लिखे और संभवत: आउटपुट बफ़रिंग को अक्षम करें क्योंकि writeपाइप के रूप में परमाणु के रूप में लंबे समय तक परमाणु होने की गारंटी दी जाती है क्योंकि वे इससे बड़े नहीं होते हैं PIPE_BUF। उदाहरण के लिए, आप यह सुनिश्चित कर सकते हैं कि यह आउटपुट बफरिंग ला और कॉल का उपयोग करता है या जो कुछ भी एक या कुछ पंक्तियों में लिखा गया है, उसके बराबर है ।stdiofflushpython

यदि आप अजगर लिपियों को संशोधित नहीं कर सकते, तो आप कर सकते हैं:

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

(GNU grep के साथ) या:

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

(यदि कमांड आउटपुट टेक्स्ट नहीं है तो नीचे टिप्पणी में नोट देखें)

और करो:

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

उन 3 lbप्रक्रियाओं से बचने का एक अन्य विकल्प यह है कि एक कमांड के लिए तीन पाइप का उपयोग किया जाए select/ pollयह देखने के लिए कि कहां से कुछ आउटपुट आ रहा है और इसे sortलाइन-आधारित को फीड करना है , लेकिन यह प्रोग्रामिंग का एक सा लेता है।


आपको waitवहां मेरी जरूरत है , मुझे लगता है।
derobert

1
नहीं, जब तक कि कुछ कार्यक्रम बाहर निकलने से पहले अपने स्टडआउट को बंद नहीं करते हैं, क्योंकि पाइप और sort -nतब तक रहेगा जब तक कि उस पर एफडी खुला होने वाले सभी कार्यक्रम बाहर निकल गए।
स्टीफन चेज़लस

वास्तव में, मैंने परीक्षण किया, आप सही हैं।
व्युत्पन्न

नहीं, मुझे अभी भी मैंगल्ड आउटपुट मिलता है। लाइनों को एक साथ मिलाया और interleaved।
सेरा

1
ठीक है @Cerales, मेरा अद्यतन उत्तर देखें
स्टीफन चेज़लस

1

फ़्लोबोक का जवाब सही समाधान था। अजीब तरह से, जीएनयू parallelका आउटपुट खराब हो जाता है अगर यह सीधे फ़ाइल में आउटपुट होता है - लेकिन अगर यह टटी पर नहीं जाता है।

सौभाग्य से, script -cएक tty की नकल करने के लिए उपलब्ध है।

अभी भी तीन स्क्रिप्ट हैं:

#!/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

फिर एक फाइल होती है जो कॉल को समांतर तक ले जाती है:

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

और फिर मैं इसे इस तरह से कॉल करता हूं:

script -c ./run_parallel > output

आउटपुट में लाइनें अलग-अलग स्क्रिप्ट के आउटपुट के बीच लाइन-बाय-लाइन मिश्रित होती हैं, लेकिन वे किसी दिए गए लाइन पर मैंगल्ड या इंटरलीव्ड नहीं होती हैं।

विचित्र व्यवहार parallel- मैं एक बग रिपोर्ट दर्ज कर सकता हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.