समानांतर प्रक्रियाओं के लिए स्टड फैलाना


13

मेरे पास एक कार्य है जो स्टडिन पर फ़ाइलों की सूची संसाधित करता है। कार्यक्रम का स्टार्ट-अप समय पर्याप्त है, और प्रत्येक फ़ाइल के समय की मात्रा व्यापक रूप से भिन्न होती है। मैं इन प्रक्रियाओं की पर्याप्त संख्या को बढ़ाना चाहता हूं, फिर जो भी काम में व्यस्त नहीं हैं उन्हें प्रेषण करें। कई अलग-अलग कमांडलाइन उपकरण हैं जो लगभग वही करते हैं जो मैं चाहता हूं, मैंने इसे लगभग दो कामकाजी विकल्पों तक सीमित कर दिया है:

find . -type f | split -n r/24 -u --filter="myjob"
find . -type f | parallel --pipe -u -l 1 myjob

समस्या यह है कि splitएक शुद्ध राउंड-रॉबिन करता है, इसलिए प्रक्रियाओं में से एक पीछे हो जाता है और पूरे ऑपरेशन के पूरा होने में देरी करता है; जबकि parallelएन लाइनों या इनपुट के बाइट्स प्रति एक प्रक्रिया को स्पॉन करना चाहता है और मैं स्टार्टअप ओवरहेड पर बहुत अधिक समय खर्च कर रहा हूं।

क्या ऐसा कुछ है जो प्रक्रियाओं को फिर से उपयोग करेगा और जो भी प्रक्रियाएँ स्टैडिन को अनब्लॉक कर चुकी हैं, उन्हें फीड करेंगी?


वह splitआज्ञा कहाँ से है? नाम मानक पाठ प्रसंस्करण उपयोगिता के साथ संघर्ष करता है ।
गाइल्स का SO- बुराई से रोकना '

@ गिल्स, यह GNU एक है: "स्प्लिट (GNU कोरुटिल्स) 8.13" । Xargs के लिए एक अजीब विकल्प के रूप में इसका उपयोग करना शायद इसका उपयोग नहीं है, लेकिन यह मेरे निकटतम है जो मुझे मिला है।
BCoates

2
मैं उस बारे में सोच रहा हूं, और एक मूलभूत समस्या यह जान रही है कि एक उदाहरण myjobअधिक इनपुट प्राप्त करने के लिए तैयार है। यह जानने का कोई तरीका नहीं है कि एक प्रोग्राम अधिक इनपुट को संसाधित करने के लिए तैयार है, आप सभी जान सकते हैं कि कुछ बफर कहीं (एक पाइप बफर, एक stdio बफर) अधिक इनपुट प्राप्त करने के लिए तैयार है। जब आप तैयार हों तो क्या आप अपने कार्यक्रम के लिए किसी प्रकार का अनुरोध भेजने का प्रबंध कर सकते हैं?
गाइल्स का SO-

यह मानते हुए कि कार्यक्रम स्टड पर bufering का उपयोग नहीं कर रहा है, एक FUSE फाइल सिस्टम जो readकॉल पर प्रतिक्रिया करता है वह चाल करेगा। यह काफी बड़ा प्रोग्रामिंग प्रयास है।
गिल्स एसओ- बुराई को रोकें '

आप आर्ग -l 1में क्यों इस्तेमाल कर रहे हैं parallel? IIRC, जो प्रति काम इनपुट की एक पंक्ति (यानी myjob के कांटे के प्रति एक फ़ाइल नाम, इतने सारे ओवरहेड ओवरहेड) को संसाधित करने के लिए समानांतर बताता है।
कैस

जवाबों:


1

यह इस तरह के एक सामान्य मामले में संभव नहीं दिखता है। इसका मतलब है कि आपके पास प्रत्येक प्रक्रिया के लिए एक बफर है और आप अगले प्रविष्टि (शेड्यूलिंग) को रखने के लिए बाहर से बफ़र्स देख सकते हैं ... बेशक आप कुछ लिख सकते हैं (या स्लम की तरह बैच सिस्टम का उपयोग कर सकते हैं)

लेकिन प्रक्रिया क्या है इसके आधार पर, आप इनपुट को प्री-प्रोसेस करने में सक्षम हो सकते हैं। उदाहरण के लिए यदि आप फ़ाइलों को डाउनलोड करना चाहते हैं, तो डीबी या इसी तरह की प्रविष्टियों को अपडेट करें, लेकिन उनमें से 50% समाप्त हो जाएंगे (और इनपुट के आधार पर आपके पास एक बड़ा प्रसंस्करण अंतर है), तो बस एक प्री-प्रोसेसर सेटअप करें यह पुष्टि करता है कि कौन सी प्रविष्टियां लंबे समय तक चलने वाली हैं (फ़ाइल मौजूद है, डेटा बदल दिया गया था, आदि), इसलिए दूसरी तरफ से जो भी आता है वह काफी समान समय लेने की गारंटी है। यहां तक ​​कि अगर हेरास्टिक सही नहीं है, तो आप काफी सुधार के साथ समाप्त हो सकते हैं। हो सकता है कि आप दूसरों को उसी तरीके से फाइल और प्रोसेस के लिए डंप करें।

लेकिन यह आपके उपयोग के मामले पर निर्भर करता है।


1

नहीं, कोई सामान्य समाधान नहीं है। आपके प्रेषणकर्ता को यह जानना होगा कि जब प्रत्येक प्रोग्राम दूसरी पंक्ति को पढ़ने के लिए तैयार है, और ऐसा कोई मानक नहीं है जिसके बारे में मुझे पता है कि इसके लिए अनुमति देता है। आप बस इतना कर सकते हैं कि STDOUT पर एक लाइन लगाई जाए और किसी चीज़ का इंतज़ार किया जाए; पाइपलाइन पर निर्माता के लिए वास्तव में एक अच्छा तरीका नहीं है यह बताने के लिए कि अगला उपभोक्ता तैयार है या नहीं।


0

मुझे ऐसा नहीं लगता। मेरी पसंदीदा मैगज़ीन में एक बार बैश प्रोग्रामिंग पर एक लेख था जो आपको चाहिए था। मैं यह मानने को तैयार हूं कि अगर ऐसा करने के लिए उपकरण होते तो वे उनका उल्लेख करते। तो आप चाहते हैं:

set -m # enable job control
max_processes=8
concurrent_processes=0

child_has_ended() { concurrent_processes=$((concurrent_processes - 1)) }

trap child_has_ended SIGCHLD # that's magic calling our bash function when a child processes ends

for i in $(find . -type f)
do
  # don't do anything while there are max_processes running
  while [ ${concurrent_processes} -ge ${max_processes}]; do sleep 0.5; done 
  # increase the counter
  concurrent_processes=$((concurrent_processes + 1))
  # start a child process to actually deal with one file
  /path/to/script/to/handle/one/file $i &
done

जाहिर है आप अपनी पसंद के हिसाब से वास्तविक कामकाजी लिपि में मंगलाचरण को बदल सकते हैं। मैंने जिस पत्रिका का उल्लेख किया है, वह शुरू में पाइपों को स्थापित करने और वास्तव में श्रमिक सूत्र शुरू करने जैसी चीजें करती है। उसके mkfifoलिए बाहर की जाँच करें , लेकिन वह मार्ग कहीं अधिक जटिल है क्योंकि कार्यकर्ता प्रक्रियाओं को मास्टर प्रक्रिया को इंगित करने की आवश्यकता है कि वे अधिक डेटा प्राप्त करने के लिए तैयार हैं। इसलिए आपको प्रत्येक कार्यकर्ता प्रक्रिया के लिए इसे डेटा के लिए एक और डेटा भेजने के लिए मास्टर प्रक्रिया के लिए एक फ़ोरो की आवश्यकता होती है।

अस्वीकरण मैंने वह स्क्रिप्ट अपने सिर के ऊपर से लिखी है। इसमें कुछ सिंटैक्स समस्याएँ हो सकती हैं।


1
यह आवश्यकताओं को पूरा नहीं करता है: आप प्रत्येक आइटम के लिए कार्यक्रम का एक अलग उदाहरण शुरू कर रहे हैं।
गिल्स एसओ- बुराई को रोकें '

यह आमतौर पर उपयोग करने के find . -type f | while read iबजाय बेहतर है for i in $(find . -type f)

0

GNU पैरेलल के लिए आप ब्लॉक का उपयोग करके सेट कर सकते हैं --ब्लॉक। हालाँकि, यह आवश्यक है कि आपके पास चलने वाली प्रत्येक प्रक्रिया के लिए 1 ब्लॉक को मेमोरी में रखने के लिए पर्याप्त मेमोरी हो।

मैं समझता हूं कि यह ठीक नहीं है कि आप क्या देख रहे हैं, लेकिन यह अभी के लिए स्वीकार्य कार्य हो सकता है।

यदि आपके कार्य औसत रूप से समान समय लेते हैं, तो आप mbuffer का उपयोग करने में सक्षम हो सकते हैं:

find . -type f | split -n r/24 -u --filter="mbuffer -m 2G | myjob"

0

इसे इस्तेमाल करे:

mkfifo प्रत्येक प्रक्रिया के लिए।

फिर tail -f | myjobप्रत्येक पंद्रह पर लटकाओ।

उदाहरण के लिए श्रमिकों की स्थापना (myjob प्रक्रिया)

mkdir /tmp/jobs
for X in 1 2 3 4
do
   mkfifo pipe$X
   tail -f pipe$X | myjob &
   jobs -l| awk '/pipe'$X'/ {print $2, "'pipe$X'"}' >> pipe-job-mapping
done

आपके आवेदन (myjob) के आधार पर, आप नौकरियों को रोकने के लिए नौकरियों का उपयोग करने में सक्षम हो सकते हैं। अन्यथा CPU द्वारा क्रमबद्ध प्रक्रियाओं को सूचीबद्ध करें और सबसे कम संसाधनों का उपभोग करने वाले का चयन करें। नौकरी रिपोर्ट की ही, उदाहरण के लिए, फ़ाइल सिस्टम में ध्वज सेट करके जब वह अधिक काम चाहता है।

यह मानते हुए कि इनपुट का उपयोग करते समय नौकरी बंद हो जाती है

jobs -sl उदाहरण के लिए, किसी रुकी हुई नौकरी का पता लगाना और उसे काम सौंपना

grep "^$STOPPED_PID" pipe-to-job-mapping | while read PID PIPE
do
   cat workset > $PIPE
done

मैंने इसके साथ परीक्षण किया

garfield:~$ cd /tmp
garfield:/tmp$ mkfifo f1
garfield:/tmp$ mkfifo f2
garfield:/tmp$ tail -f f1 | sed 's/^/1 /' &
[1] 21056
garfield:/tmp$ tail -f f2 | sed 's/^/2 /' &
[2] 21058
garfield:/tmp$ echo hello > f1
1 hello
garfield:/tmp$ echo what > f2
2 what
garfield:/tmp$ echo yes > f1
1 yes

यह मैं मानता हूँ बस इतना मनगढ़ंत था ymmv।


0

इसे हल करने के लिए वास्तव में क्या आवश्यक है यह किसी प्रकार का एक कतार तंत्र है।

क्या नौकरियों को उनके इनपुट को क्यू से पढ़ना संभव है, जैसे कि SYSV संदेश कतार, और फिर समानांतर द्वारा चलाए जाने वाले प्रोग्रामों को क्यू पर मानों को धक्का देना है?

एक अन्य संभावना कतार के लिए एक निर्देशिका का उपयोग करने की है, इस तरह:

  1. खोज आउटपुट एक डायरेक्टरी में प्रोसेस करने के लिए प्रत्येक फाइल के लिए एक सिमलिंक बनाता है, pending
  2. प्रत्येक कार्य प्रक्रिया mvपहली फ़ाइल को निर्देशिका में देखती है pending, जिसका नाम सिबलिंग डाइरेक्टरी है inprogress
  3. अगर नौकरी सफलतापूर्वक फ़ाइल को स्थानांतरित कर देती है, तो यह प्रसंस्करण करता है; अन्यथा, यह किसी अन्य फ़ाइलनाम को खोजने और स्थानांतरित करने के लिए वापस जाता हैpending

0

@ राख के उत्तर को उजागर करने के लिए, आप कार्य को वितरित करने के लिए एक SYSV संदेश कतार का उपयोग कर सकते हैं। यदि आप C में अपना प्रोग्राम नहीं लिखना चाहते हैं, तो एक उपयोगिता है जिसे ipcmdमदद मिल सकती है। यहाँ है कि मैं क्या एक साथ रखा के उत्पादन में पारित करने के लिए है find $DIRECTORY -type fकरने के लिए $PARALLELप्रक्रियाओं की संख्या:

set -o errexit
set -o nounset

export IPCMD_MSQID=$(ipcmd msgget)

DIRECTORY=$1
PARALLEL=$2

# clean up message queue on exit
trap 'ipcrm -q $IPCMD_MSQID' EXIT

for i in $(seq $PARALLEL); do
   {
      while true
      do
          message=$(ipcmd msgrcv) || exit
          [ -f $message ] || break
          sleep $((RANDOM/3000))
      done
   } &
done

find "$DIRECTORY" -type f | xargs ipcmd msgsnd

for i in $(seq $PARALLEL); do
   ipcmd msgsnd "/dev/null/bar"
done
wait

यहाँ एक परीक्षण रन है:

$ for i in $(seq 20 10 100) ; do time parallel.sh /usr/lib/ $i ; done
parallel.sh /usr/lib/ $i  0.30s user 0.67s system 0% cpu 1:57.23 total
parallel.sh /usr/lib/ $i  0.28s user 0.69s system 1% cpu 1:09.58 total
parallel.sh /usr/lib/ $i  0.19s user 0.80s system 1% cpu 1:05.29 total
parallel.sh /usr/lib/ $i  0.29s user 0.73s system 2% cpu 44.417 total
parallel.sh /usr/lib/ $i  0.25s user 0.80s system 2% cpu 37.353 total
parallel.sh /usr/lib/ $i  0.21s user 0.85s system 3% cpu 32.354 total
parallel.sh /usr/lib/ $i  0.30s user 0.82s system 3% cpu 28.542 total
parallel.sh /usr/lib/ $i  0.27s user 0.88s system 3% cpu 30.219 total
parallel.sh /usr/lib/ $i  0.34s user 0.84s system 4% cpu 26.535 total

0

जब तक आप अनुमान नहीं लगा सकते हैं कि किसी विशेष इनपुट फ़ाइल को कब तक संसाधित किया जाएगा और कार्यकर्ता प्रक्रियाओं को अनुसूचक को रिपोर्ट करने का एक तरीका नहीं है (जैसा कि वे सामान्य समानांतर कंप्यूटिंग परिदृश्यों में करते हैं - अक्सर एमपीआई के माध्यम से ), आप आम तौर पर भाग्य से बाहर होते हैं - या तो इनपुट की असमानता () की वजह से कुछ श्रमिकों के इनपुट का जुर्माना दूसरों की तुलना में लंबे समय तक चुकाते हैं, या हर इनपुट फ़ाइल के लिए एक नई प्रक्रिया को शुरू करने के लिए जुर्माना देना पड़ता है।


0

पिछले 7 वर्षों में जीएनयू समानांतर बदल गया है। तो आज यह कर सकते हैं:

यह उदाहरण दिखाता है कि प्रक्रिया 4 और 5 की तुलना में 11 और 10 की प्रक्रिया के लिए अधिक ब्लॉक दिए गए हैं क्योंकि 4 और 5 धीमे हैं:

seq 1000000 |
  parallel -j8 --tag --roundrobin --pipe --block 1k 'pv -qL {}0000 | wc' ::: 11 4 5 6 9 8 7 10
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.