अजगर बहुउद्देशीय प्रतीक्षा तक सभी धागे समाप्त हो गए


119

यह एक समान संदर्भ में पूछा गया हो सकता है, लेकिन मैं लगभग 20 मिनट की खोज के बाद एक उत्तर खोजने में असमर्थ था, इसलिए मैं पूछूंगा।

मैंने एक पाइथन स्क्रिप्ट लिखी है (बताएं: scriptA.py) और एक स्क्रिप्ट (स्क्रिप्ट स्क्रिप्ट को कहने देता है)

ScriptB में मैं अलग-अलग तर्कों के साथ scriptA को कई बार कॉल करना चाहता हूं, प्रत्येक बार चलाने में लगभग एक घंटे का समय लगता है, (इसकी एक विशाल स्क्रिप्ट, बहुत सारी चीज़ें होती है .. इसके बारे में चिंता न करें) और मैं इसे चलाने में सक्षम होना चाहता हूं एक साथ सभी अलग-अलग तर्कों के साथ स्क्रिप्टए, लेकिन मुझे तब तक इंतजार करने की आवश्यकता है जब तक कि सभी जारी रखने से पहले नहीं हो जाते; मेरा कोड:

import subprocess

#setup
do_setup()

#run scriptA
subprocess.call(scriptA + argumentsA)
subprocess.call(scriptA + argumentsB)
subprocess.call(scriptA + argumentsC)

#finish
do_finish()

मैं subprocess.call()एक ही समय में सभी को चलाना चाहता हूं , और तब तक प्रतीक्षा करें जब तक वे सभी काम न कर लें, मुझे यह कैसे करना चाहिए?

मैंने यहाँ उदाहरण की तरह थ्रेडिंग का उपयोग करने की कोशिश की :

from threading import Thread
import subprocess

def call_script(args)
    subprocess.call(args)

#run scriptA   
t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))
t1.start()
t2.start()
t3.start()

लेकिन मुझे नहीं लगता कि यह सही है।

मुझे कैसे पता चलेगा कि मेरे जाने से पहले वे सब खत्म कर चुके हैं do_finish()?

जवाबों:


150

आपको स्क्रिप्ट के अंत में ऑब्जेक्ट की विधि में शामिल होने की आवश्यकता है Thread

t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()

इस प्रकार मुख्य धागा तक इंतजार होगा t1, t2और t3निष्पादन समाप्त होगा।


5
हम्म् - कुछ समझने में परेशानी हो रही है, यह पहला रन टी 1 नहीं है, इसके खत्म होने तक प्रतीक्षा करें, फिर t2..etc, आदि पर जाएं? यह सब एक साथ कैसे होता है? मैं नहीं देखता कि यह उन्हें एक ही समय में कैसे चलाएगा?
इबर रोज

25
joinजब तक थ्रेड निष्पादन समाप्त नहीं हो जाता है, तब तक ब्लॉक को कॉल करें । आप वैसे भी सभी धागे के लिए इंतजार करना होगा। यदि t1पहले खत्म हो जाता है तो आप इंतजार करना शुरू कर देंगे t2(जो पहले से ही समाप्त हो सकता है और आप तुरंत इंतजार करने के लिए आगे बढ़ेंगे t3)। यदि t1आपको निष्पादित करने में सबसे लंबा समय लगता है, जब आप इसे दोनों से लौटाते हैं t1और t2बिना अवरुद्ध किए तुरंत वापस आ जाएंगे।
मक्सिम स्केरडज़िन

1
यदि आप मेरे प्रश्न को नहीं समझते हैं - यदि मैं उपरोक्त कोड को अपने कोड में कॉपी करता हूं - तो यह काम करेगा? या क्या मैं कुछ न कुछ भूल रहा हूं?
इबर रोज

2
ठीक है मैं देखता हूँ। अब मैं समझता हूँ, इसके बारे में थोड़ा उलझन में था, लेकिन मुझे लगता है कि मैं समझता हूँ, joinवर्तमान प्रक्रिया को थ्रेड में संलग्न करता है और इसके पूर्ण होने तक प्रतीक्षा करता है, और यदि t2 t1 से पहले समाप्त हो जाता है, तो जब t1 किया जाता है, तो यह t2 के लिए जाँच करेगा। यह है, और फिर t3..etc..etc .. की जांच करें और उसके बाद ही जब सब पूरा हो जाए तो यह जारी रहेगा। बहुत बढ़िया।
इबर रोज

3
t1 को सबसे लंबा समय लगता है, लेकिन t2 में एक अपवाद है। फिर क्या होता है? क्या आप उस अपवाद को पकड़ सकते हैं या जाँच सकते हैं कि t2 समाप्त हुआ या नहीं?
सिप्रियन टॉमोयागै

174

थ्रेड्स को एक सूची में रखें और फिर जॉइन विधि का उपयोग करें

 threads = []

 t = Thread(...)
 threads.append(t)

 ...repeat as often as necessary...

 # Start all threads
 for x in threads:
     x.start()

 # Wait for all of them to finish
 for x in threads:
     x.join()

1
हां, यह काम करेगा लेकिन समझना कठिन है। आपको हमेशा कॉम्पैक्ट कोड और "पठनीयता" के बीच संतुलन खोजने की कोशिश करनी चाहिए। याद रखें: कोड एक बार लिखा जाता है लेकिन कई बार पढ़ा जाता है। इसलिए यह अधिक महत्वपूर्ण है कि इसे समझना आसान है।
हारून दिगुल्ला

2
"फ़ैक्टरी पैटर्न" कुछ ऐसा नहीं है जिसे मैं एक वाक्य में समझा सकता हूं। इसके लिए Google और stackoverflow.com पर खोजें। कई उदाहरण और स्पष्टीकरण हैं। संक्षेप में: आप कोड लिखते हैं जो आपके लिए कुछ जटिल बनाता है। एक वास्तविक कारखाने की तरह: आप एक ऑर्डर देते हैं और एक तैयार उत्पाद वापस प्राप्त करते हैं।
आरोन दिगुल्ला

18
मुझे इसके दुष्प्रभावों के लिए सूची समझ का उपयोग करने का विचार पसंद नहीं है और परिणामी सूची के साथ कुछ भी उपयोगी नहीं है। लूप के लिए एक सरल क्लीनर होगा भले ही यह दो पंक्तियों में फैला हो ...
Ioan Alexandru Cucu

1
@ ऐरॉन डिगुल मुझे समझ में आ गया है। मेरा क्या मतलब है कि मैं for x in threads: x.join()सूची संकलन का उपयोग करने के बजाय सिर्फ करूंगा
इयान अलेक्जेंड्रू

1
@ इऑनएलेक्सैंड्रुक्यू: मैं अब भी सोच रहा हूं कि क्या अधिक पठनीय और कुशल समाधान है: stackoverflow.com/questions/21428602/…
आरोन डिगुल्ला

29

Python3 में, Python 3.2 के बाद से उसी परिणाम तक पहुंचने के लिए एक नया दृष्टिकोण है, जिसे मैं व्यक्तिगत रूप से पारंपरिक थ्रेड क्रिएशन / स्टार्ट / जॉइन, पैकेज concurrent.futures: https://docs.python.org/3/library/concurrent.finures पर पसंद करता हूं। .html

ThreadPoolExecutorकोड का उपयोग करना होगा:

from concurrent.futures.thread import ThreadPoolExecutor
import time

def call_script(ordinal, arg):
    print('Thread', ordinal, 'argument:', arg)
    time.sleep(2)
    print('Thread', ordinal, 'Finished')

args = ['argumentsA', 'argumentsB', 'argumentsC']

with ThreadPoolExecutor(max_workers=2) as executor:
    ordinal = 1
    for arg in args:
        executor.submit(call_script, ordinal, arg)
        ordinal += 1
print('All tasks has been finished')

पिछले कोड का आउटपुट कुछ इस प्रकार है:

Thread 1 argument: argumentsA
Thread 2 argument: argumentsB
Thread 1 Finished
Thread 2 Finished
Thread 3 argument: argumentsC
Thread 3 Finished
All tasks has been finished

एक लाभ यह है कि आप अधिकतम समवर्ती श्रमिकों को स्थापित करने वाले थ्रूपुट को नियंत्रित कर सकते हैं।


लेकिन आप कैसे बता सकते हैं कि जब थ्रेडपूल के सभी धागे समाप्त हो गए हैं?
प्राइम बाय डिजाइन

1
जैसा कि आप उदाहरण में देख सकते हैं, withस्टेटमेंट के बाद का कोड निष्पादित किया जाता है जब सभी कार्य समाप्त हो जाते हैं।
रॉबर्टो

यह काम नहीं करता है। धागे में वास्तव में लंबे समय से कुछ करने की कोशिश करें। थ्रेड फिनिश से पहले आपका प्रिंट स्टेटमेंट निष्पादित होगा
प्राणले

@Pranalee, यह कोड काम करता है, मैंने आउटपुट लाइनों को जोड़ने के लिए कोड अपडेट किया है। सभी सूत्र समाप्त होने से पहले आप "ऑल टास्क ..." नहीं देख सकते, withइस तरह से इस मामले में डिजाइन द्वारा स्टेटमेंट काम करता है। वैसे भी, आप हमेशा एसओ में एक नया प्रश्न खोल सकते हैं और अपना कोड पोस्ट कर सकते हैं ताकि हम आपको यह पता लगाने में मदद कर सकें कि आपके मामले में क्या हो रहा है।
राबर्टो

@PrimeByDesign आप concurrent.futures.waitफ़ंक्शन का उपयोग कर सकते हैं , आप यहां एक वास्तविक उदाहरण देख सकते हैं आधिकारिक डॉक्स: docs.python.org/3/library/…
अलेक्जेंडर फोर्टिन

28

मैं एक इनपुट सूची के आधार पर सूची समझ का उपयोग करना पसंद करता हूं:

inputs = [scriptA + argumentsA, scriptA + argumentsB, ...]
threads = [Thread(target=call_script, args=(i)) for i in inputs]
[t.start() for t in threads]
[t.join() for t in threads]

चेक किया गया उत्तर अच्छी तरह से समझाता है लेकिन यह छोटा है और इसे बदसूरत दोहराव की आवश्यकता नहीं है। बस एक अच्छा जवाब है। :)
tleb

साइड इफेक्ट के लिए सूची की समझ आमतौर पर मूल्यह्रास * है। लेकिन इस उपयोग के मामले में, यह एक अच्छा विचार है। * stackoverflow.com/questions/5753597/…
विनायक कनियारक्कल

3
@VinayakKaniyarakkal for t in threads:t.start()क्या यह बेहतर नहीं है?
स्मार्टमनोज

5

आपके पास कुछ इस तरह की कक्षा हो सकती है, जिसमें से आप 'n' संख्या जोड़ सकते हैं फ़ंक्शन या कंसोल_ स्क्रिप्ट जो आप समानांतर जुनून में निष्पादित करना चाहते हैं और निष्पादन शुरू करते हैं और सभी नौकरियों के पूरा होने की प्रतीक्षा करते हैं।

from multiprocessing import Process

class ProcessParallel(object):
    """
    To Process the  functions parallely

    """    
    def __init__(self, *jobs):
        """
        """
        self.jobs = jobs
        self.processes = []

    def fork_processes(self):
        """
        Creates the process objects for given function deligates
        """
        for job in self.jobs:
            proc  = Process(target=job)
            self.processes.append(proc)

    def start_all(self):
        """
        Starts the functions process all together.
        """
        for proc in self.processes:
            proc.start()

    def join_all(self):
        """
        Waits untill all the functions executed.
        """
        for proc in self.processes:
            proc.join()


def two_sum(a=2, b=2):
    return a + b

def multiply(a=2, b=2):
    return a * b


#How to run:
if __name__ == '__main__':
    #note: two_sum, multiply can be replace with any python console scripts which
    #you wanted to run parallel..
    procs =  ProcessParallel(two_sum, multiply)
    #Add all the process in list
    procs.fork_processes()
    #starts  process execution 
    procs.start_all()
    #wait until all the process got executed
    procs.join_all()

यह बहुविकल्पी है। प्रश्न docs.python.org/3/library/threading.html
रुस्तम ए।

3

से threading मॉड्यूल प्रलेखन

एक "मुख्य सूत्र" वस्तु है; यह पायथन कार्यक्रम में नियंत्रण के प्रारंभिक धागे से मेल खाती है। यह एक डेमॉन धागा नहीं है।

ऐसी संभावना है कि "डमी थ्रेड ऑब्जेक्ट्स" बनाए गए हैं। ये "विदेशी धागे" से संबंधित थ्रेड ऑब्जेक्ट हैं, जो थ्रेडिंग मॉड्यूल के बाहर शुरू होने वाले नियंत्रण के धागे हैं, जैसे कि सीधे सी कोड से। डमी थ्रेड ऑब्जेक्ट्स में सीमित कार्यक्षमता है; उन्हें हमेशा जीवित और शैतानी माना जाता है, और उन्हें join()एड नहीं किया जा सकता है । वे कभी नष्ट नहीं होते हैं, क्योंकि विदेशी धागे की समाप्ति का पता लगाना असंभव है।

इसलिए, उन दो मामलों को पकड़ने के लिए जब आप अपने द्वारा बनाए गए धागों की सूची रखने में रुचि नहीं रखते हैं:

import threading as thrd


def alter_data(data, index):
    data[index] *= 2


data = [0, 2, 6, 20]

for i, value in enumerate(data):
    thrd.Thread(target=alter_data, args=[data, i]).start()

for thread in thrd.enumerate():
    if thread.daemon:
        continue
    try:
        thread.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err.args[0]:
            # catchs main thread
            continue
        else:
            raise

जिस:

>>> print(data)
[0, 4, 12, 40]

2

शायद, कुछ इस तरह

for t in threading.enumerate():
    if t.daemon:
        t.join()

मैंने इस कोड की कोशिश की है, लेकिन इसके काम के बारे में सुनिश्चित नहीं है क्योंकि मेरे कोड का अंतिम निर्देश मुद्रित किया गया था जो लूप के लिए इसके बाद था और फिर भी प्रक्रिया समाप्त नहीं हुई थी।
ओंकार

1

मुझे बस उसी समस्या का सामना करना पड़ा जहाँ मुझे उन सभी धागों की प्रतीक्षा करने की आवश्यकता थी जो लूप के लिए बनाए गए थे। मैंने कोड के निम्नलिखित टुकड़े को आज़माया। यह सही समाधान नहीं हो सकता है, लेकिन मुझे लगा कि यह एक सरल समाधान होगा। मापना:

for t in threading.enumerate():
    try:
        t.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err:
            continue
        else:
            raise
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.