पायथन थ्रेडिंग में शामिल होने () का क्या उपयोग है?


197

मैं अजगर के थ्रेडिंग का अध्ययन कर रहा था और भर आया join()

लेखक ने बताया कि यदि धागा डेमॉन मोड में है, तो मुझे उपयोग करने की आवश्यकता है join()ताकि मुख्य धागा समाप्त होने से पहले धागा खुद को खत्म कर सके।

लेकिन मैंने भी उसका उपयोग करते हुए देखा है t.join(), हालांकि tनहीं थाdaemon

उदाहरण कोड यह है

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )

def daemon():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')

d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)

def non_daemon():
    logging.debug('Starting')
    logging.debug('Exiting')

t = threading.Thread(name='non-daemon', target=non_daemon)

d.start()
t.start()

d.join()
t.join()

मुझे नहीं पता कि इसका क्या उपयोग है t.join()क्योंकि यह डेमॉन नहीं है और मैं इसे हटाने पर भी कोई बदलाव नहीं देख सकता


13
शीर्षक के लिए +1। 'जॉइन' को विशेष रूप से खराब प्रदर्शन को प्रोत्साहित करने के लिए डिज़ाइन किया गया है, (थ्रेड को लगातार बनाने / समाप्त करने / नष्ट करने के लिए), जीयूआई लॉकअप, (ईवेंट हैंडलर में प्रतीक्षा) और ऐप शटडाउन विफलताओं, (समाप्त करने के लिए अबाधित थ्रेड्स की प्रतीक्षा)। नोट - केवल पायथन नहीं है, यह एक क्रॉस-भाषा विरोधी पैटर्न है।
मार्टिन जेम्स

जवाबों:


287

तंत्र को प्रदर्शित करने के लिए कुछ हद तक अनाड़ी-कला: join()मुख्य रूप से मुख्य सूत्र द्वारा कहा जाता है। इसे एक और सूत्र द्वारा भी कहा जा सकता है, लेकिन यह आरेख को जटिल रूप से जटिल करेगा।

join-कॉलिंग को मुख्य-धागे के ट्रैक में रखा जाना चाहिए, लेकिन थ्रेड-रिलेशन को व्यक्त करने के लिए और इसे जितना संभव हो उतना सरल रखने के लिए, मैं इसे बाल-धागे में जगह देना चुनता हूं।

without join:
+---+---+------------------                     main-thread
    |   |
    |   +...........                            child-thread(short)
    +..................................         child-thread(long)

with join
+---+---+------------------***********+###      main-thread
    |   |                             |
    |   +...........join()            |         child-thread(short)
    +......................join()......         child-thread(long)

with join and daemon thread
+-+--+---+------------------***********+###     parent-thread
  |  |   |                             |
  |  |   +...........join()            |        child-thread(short)
  |  +......................join()......        child-thread(long)
  +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,     child-thread(long + daemonized)

'-' main-thread/parent-thread/main-program execution
'.' child-thread execution
'#' optional parent-thread execution after join()-blocked parent-thread could 
    continue
'*' main-thread 'sleeping' in join-method, waiting for child-thread to finish
',' daemonized thread - 'ignores' lifetime of other threads;
    terminates when main-programs exits; is normally meant for 
    join-independent tasks

तो इसका कारण यह है कि आप कोई बदलाव नहीं देखते हैं क्योंकि आपका मुख्य-सूत्र आपके बाद कुछ भी नहीं करता है join। आप कह सकते हैं joinकि (केवल) मुख्य-सूत्र के निष्पादन-प्रवाह के लिए प्रासंगिक है।

यदि, उदाहरण के लिए, आप समवर्ती रूप से पृष्ठों का एक गुच्छा डाउनलोड करना चाहते हैं, तो उन्हें एक ही बड़े पृष्ठ में समाहित करें, आप थ्रेड्स का उपयोग करके समवर्ती डाउनलोड शुरू कर सकते हैं, लेकिन जब तक आप किसी एकल पृष्ठ को समेटना शुरू नहीं करते हैं, तब तक इंतजार करना होगा। बहुत से। जब आप उपयोग करते हैं join()


कृपया पुष्टि करें कि कार्यक्रम के निष्पादन को अवरुद्ध किए बिना एक निष्क्रिय धागा शामिल हो सकता है ()?
एविएटर ४५००३

@ Aviator45003: हाँ, की तरह समय समाप्ति तर्क का उपयोग करके: demon_thread.join(0.0), join()डिफ़ॉल्ट daemonized विशेषता के संबंध के बिना अवरुद्ध करके है। लेकिन एक डिमाण्ड थ्रेड में शामिल होने से सबसे अधिक परेशानी की संभावना है! अब मैं join()डेमन-थ्रेड के लिए अपने छोटे चित्र में कॉल को हटाने पर विचार कर रहा हूं ...
डॉन प्रश्न

@DonQuestion तो अगर हम कोड के अंत में की जरूरत है अगर हम पर सेट daemon=Trueनहीं है ? join()join()
बेनामिन जाफरी

@ बेनीमीनजफरी: हां। यदि नहीं, तो मुख्य-सूत्र (= प्रोग्राम) बाहर निकल जाएगा, यदि केवल डेमन-थ्रेड शेष है। लेकिन एक (अजगर) डेमन थ्रेड की प्रकृति यह है कि अगर यह बैकग्राउंड टास्क अभी भी चल रहा है तो मुख्य थ्रेड को कोई परवाह नहीं है। मैं इस बारे में सोचूंगा कि उस मुद्दे को कैसे स्पष्ट किया जाए, उस मुद्दे को स्पष्ट किया जाए। आपके कमेंट के लिए धन्यवाद!
डॉन प्रश्न १

पहले मामले में, जब main threadखत्म होता है, तो कार्यक्रम को खत्म child-thread(long)करने के लिए खुद को चलाने के बिना खत्म हो जाएगा (यानी child-thread(long)पूरी तरह से नहीं किया गया है)?
स्काईट्री

65

डॉक्स से सीधे

जुड़ना ([टाइमआउट]) जब तक धागा समाप्त न हो जाए, तब तक प्रतीक्षा करें। यह कॉलिंग थ्रेड को तब तक ब्लॉक करता है जब तक कि थ्रेड (ज्वाइन) विधि को टर्मिनेट नहीं किया जाता है - या तो सामान्य रूप से या अनहैंड किए गए अपवाद के माध्यम से - या जब तक वैकल्पिक टाइमआउट नहीं होता है।

इसका मतलब है कि मुख्य धागा जो स्पॉन करता है tऔर d, tखत्म होने तक इंतजार करता है ।

आपके प्रोग्राम में नियोजित तर्क के आधार पर, आप तब तक इंतजार करना चाहते हैं जब तक कि आपका मुख्य धागा जारी रहने से पहले एक धागा खत्म नहीं हो जाता।

डॉक्स से भी:

एक धागे को "डेमन थ्रेड" के रूप में चिह्नित किया जा सकता है। इस ध्वज का महत्व यह है कि पूरे पायथन कार्यक्रम से बाहर निकलता है जब केवल डेमन थ्रेड्स बचे होते हैं।

एक सरल उदाहरण, कहें कि हमारे पास यह है:

def non_daemon():
    time.sleep(5)
    print 'Test non-daemon'

t = threading.Thread(name='non-daemon', target=non_daemon)

t.start()

जिसके साथ खत्म होता है:

print 'Test one'
t.join()
print 'Test two'

यह आउटपुट होगा:

Test one
Test non-daemon
Test two

यहां मास्टर थ्रेड स्पष्ट रूप से tथ्रेड के समाप्त होने तक प्रतीक्षा करता है जब तक कि printवह दूसरी बार कॉल न करे ।

वैकल्पिक रूप से अगर हमारे पास यह था:

print 'Test one'
print 'Test two'
t.join()

हम इसे प्राप्त करेंगे:

Test one
Test two
Test non-daemon

यहां हम मुख्य धागे में अपना काम करते हैं और फिर हम tधागे के खत्म होने का इंतजार करते हैं । इस मामले में हम स्पष्ट जुड़ाव को भी हटा सकते हैं t.join()और कार्यक्रम tसमाप्त होने की प्रतीक्षा करेगा ।


तुम मेरे कोड के लिए कुछ chnage कर सकते हैं ताकि मैं का अंतर देख सकते हैं t.join()। सोया नींद या कुछ और जोड़कर। फिलहाल मैं कार्यक्रम में किसी भी प्रकार का नरसंहार देख सकता हूं, भले ही मैं इसका उपयोग करूं या नहीं। लेकिन अगर मैं उपयोग नहीं d.join()करता हूं, तो मैं इसके निकास को देख सकता हूं, जब मैं d.join का उपयोग नहीं करता हूं ()
user192362127

34

इस धागे के लिए धन्यवाद - इसने मुझे बहुत मदद की।

मैंने आज .join () के बारे में कुछ सीखा।

ये धागे समानांतर में चलते हैं:

d.start()
t.start()
d.join()
t.join()

और ये क्रमिक रूप से चलते हैं (जो मैं चाहता था):

d.start()
d.join()
t.start()
t.join()

विशेष रूप से, मैं चतुर और चुस्त होने की कोशिश कर रहा था:

class Kiki(threading.Thread):
    def __init__(self, time):
        super(Kiki, self).__init__()
        self.time = time
        self.start()
        self.join()

यह काम! लेकिन यह क्रमिक रूप से चलता है। मैं __ init __ में self.start () लगा सकता हूं, लेकिन self.join () नहीं। जो हर धागे को शुरू करने के बाद किया जाना चाहिए ।

जुड़ना () वह है जो आपके धागे के खत्म होने का इंतजार करने के लिए मुख्य धागा का कारण बनता है। अन्यथा, आपका धागा सभी अपने आप चलता है।

तो जुड़ने के बारे में सोचने का एक तरीका () मुख्य धागे पर "पकड़" के रूप में - यह आपके धागे को डी-थ्रेड करता है और मुख्य धागे में क्रमिक रूप से निष्पादित होता है, इससे पहले कि मुख्य धागा जारी रह सकता है। यह आश्वस्त करता है कि मुख्य धागा आगे बढ़ने से पहले आपका धागा पूरा हो गया है। ध्यान दें कि इसका मतलब यह ठीक है अगर आप जुड़ने से पहले अपने धागे को समाप्त कर चुके हैं () - मुख्य धागा बस तुरंत छोड़ दिया जाता है जब जुड़ना () कहा जाता है।

वास्तव में, यह अभी मेरे साथ होता है कि मुख्य धागा d.join () पर इंतजार करता है जब तक कि धागा d खत्म नहीं होता इससे पहले कि वह t.join () पर चले।

वास्तव में, बहुत स्पष्ट होने के लिए, इस कोड पर विचार करें:

import threading
import time

class Kiki(threading.Thread):
    def __init__(self, time):
        super(Kiki, self).__init__()
        self.time = time
        self.start()

    def run(self):
        print self.time, " seconds start!"
        for i in range(0,self.time):
            time.sleep(1)
            print "1 sec of ", self.time
        print self.time, " seconds finished!"


t1 = Kiki(3)
t2 = Kiki(2)
t3 = Kiki(1)
t1.join()
print "t1.join() finished"
t2.join()
print "t2.join() finished"
t3.join()
print "t3.join() finished"

यह इस आउटपुट का उत्पादन करता है (ध्यान दें कि प्रिंट स्टेटमेंट एक दूसरे में कैसे पिरोए गए हैं।)

$ python test_thread.py
32   seconds start! seconds start!1

 seconds start!
1 sec of  1
 1 sec of 1  seconds finished!
 21 sec of
3
1 sec of  3
1 sec of  2
2  seconds finished!
1 sec of  3
3  seconds finished!
t1.join() finished
t2.join() finished
t3.join() finished
$ 

T1.join () मुख्य धागा धारण कर रहा है। सभी तीन धागे t1.join () के पूरा होने से पहले पूरा हो जाता है और मुख्य धागा प्रिंट को निष्पादित करने के लिए आगे बढ़ता है फिर t2.join () फिर प्रिंट तब t3.join () प्रिंट होता है।

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

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


अरे, मैं थ्रेडिंग के लिए भी नया हूं और मुख्य धागे के बारे में उलझन में हूं, क्या पहला धागा मुख्य धागा है, यदि नहीं, तो कृपया मेरा मार्गदर्शन करें?
रोहित खत्री

मुख्य सूत्र कार्यक्रम ही है। प्रत्येक धागे को वहां से कांटा जाता है। फिर उन्हें वापस जोड़ दिया जाता है - क्योंकि कमांड जॉइन होने पर (), प्रोग्राम तब तक इंतजार करता है जब तक कि थ्रेड समाप्त नहीं हो जाता है जब तक कि इसे निष्पादित करना जारी रहता है।
किकी ज्वेल

15

विधि में शामिल हों ()

कॉलिंग थ्रेड को तब तक ब्लॉक करता है जब तक कि थ्रेड () विधि को शामिल नहीं किया जाता है।

स्रोत: http://docs.python.org/2/library/threading.html


14
तो जुड़ने का क्या फायदा है? ओपी प्रश्न देखें, केवल डॉक्स को मत छोड़े
डॉन प्रश्न

@DonQuestion मैंने भी बिना उपयोग के बिना गैर-डीमन धागे में sleep.timer (20) को जोड़ने की कोशिश की t.join()और समाप्ति से पहले अभी भी इसके लिए इंतजार कर रहा है। मुझे t.join()यहाँ अपने कोड का कोई उपयोग नहीं दिखाई दे रहा है
user192362127

आगे स्पष्टीकरण के लिए मेरा जवाब देखें। अपने नींद के बारे में। गैर-दानव में -> एक दानव-धागा उसके माता-पिता के जीवन-समय से अलग होता है और इसलिए माता-पिता / भाई-बहन धागे के जीवन-काल से प्रभावित नहीं होंगे और इसके विपरीत ।
डॉन प्रश्न

2
The जॉइन ’और 'ब्लॉक’ शब्दावली गूंज रही है। 'अवरुद्ध' से यह पता चलता है कि कॉलिंग प्रक्रिया को किसी भी संख्या में ऐसा करने से रोक दिया गया है जो अभी भी करना है, जबकि वास्तव में यह केवल समाप्त होने (ओएस पर लौटने) से अवरुद्ध है, अधिक नहीं। एक ही टोकन के द्वारा, यह इतना स्पष्ट नहीं है कि एक मुख्य धागा है जो एक बच्चे के धागे को 'ज्वाइन' (यानी समाप्त) करता है। तो, डॉन क्यू, स्पष्टीकरण के लिए धन्यवाद।
रॉल्फब्ली

4

सरल समझ,

जुड़ने के साथ - दुभाषिया तब तक इंतजार करेगा जब तक आपकी प्रक्रिया पूरी या समाप्त नहीं हो जाती

>>> from threading import Thread
>>> import time
>>> def sam():
...   print 'started'
...   time.sleep(10)
...   print 'waiting for 10sec'
... 
>>> t = Thread(target=sam)
>>> t.start()
started

>>> t.join() # with join interpreter will wait until your process get completed or terminated
done?   # this line printed after thread execution stopped i.e after 10sec
waiting for 10sec
>>> done?

शामिल होने के बिना - दुभाषिया अभ्यस्त इंतजार जब तक प्रक्रिया समाप्त हो ,

>>> t = Thread(target=sam)
>>> t.start()
started
>>> print 'yes done' #without join interpreter wont wait until process get terminated
yes done
>>> waiting for 10sec

1

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


1

अजगर में 3.x join () का उपयोग मुख्य धागे के साथ एक थ्रेड को जोड़ने के लिए किया जाता है अर्थात जब ज्वाइन () एक विशेष थ्रेड के लिए उपयोग किया जाता है तो मुख्य थ्रेड तब तक निष्पादित करना बंद कर देगा जब तक कि सम्मिलित थ्रेड का निष्पादन पूरा नहीं हो जाता।

#1 - Without Join():
import threading
import time
def loiter():
    print('You are loitering!')
    time.sleep(5)
    print('You are not loitering anymore!')

t1 = threading.Thread(target = loiter)
t1.start()
print('Hey, I do not want to loiter!')
'''
Output without join()--> 
You are loitering!
Hey, I do not want to loiter!
You are not loitering anymore! #After 5 seconds --> This statement will be printed

'''
#2 - With Join():
import threading
import time
def loiter():
    print('You are loitering!')
    time.sleep(5)
    print('You are not loitering anymore!')

t1 = threading.Thread(target = loiter)
t1.start()
t1.join()
print('Hey, I do not want to loiter!')

'''
Output with join() -->
You are loitering!
You are not loitering anymore! #After 5 seconds --> This statement will be printed
Hey, I do not want to loiter! 

'''

0

यह उदाहरण .join()कार्रवाई को प्रदर्शित करता है:

import threading
import time

def threaded_worker():
    for r in range(10):
        print('Other: ', r)
        time.sleep(2)

thread_ = threading.Timer(1, threaded_worker)
thread_.daemon = True  # If the main thread kills, this thread will be killed too. 
thread_.start()

flag = True

for i in range(10):
    print('Main: ', i)
    time.sleep(2)
    if flag and i > 4:
        print(
            '''
            Threaded_worker() joined to the main thread. 
            Now we have a sequential behavior instead of concurrency.
            ''')
        thread_.join()
        flag = False

बाहर:

Main:  0
Other:  0
Main:  1
Other:  1
Main:  2
Other:  2
Main:  3
Other:  3
Main:  4
Other:  4
Main:  5
Other:  5

            Threaded_worker() joined to the main thread. 
            Now we have a sequential behavior instead of concurrency.

Other:  6
Other:  7
Other:  8
Other:  9
Main:  6
Main:  7
Main:  8
Main:  9

0

मुख्य सूत्र (या किसी अन्य थ्रेड) के अन्य थ्रेड्स में शामिल होने के लिए कुछ कारण हैं

  1. एक धागा ने कुछ संसाधनों का निर्माण या धारण (लॉकिंग) किया हो सकता है। जॉइन-कॉलिंग थ्रेड अपनी ओर से संसाधनों को साफ करने में सक्षम हो सकता है

  2. join () कहा जाता है कि थ्रेड समाप्त होने के बाद जॉइन-कॉलिंग थ्रेड के लिए एक प्राकृतिक अवरोधक कॉल है।

यदि एक अजगर कार्यक्रम अन्य थ्रेड्स में शामिल नहीं होता है, तो अजगर दुभाषिया अभी भी अपनी ओर से गैर-डेमन थ्रेड्स में शामिल हो जाएगा।


-2

"जॉइन ऑफ़ यूज़ () का उपयोग क्या है?" तुम कहो। वास्तव में, यह उसी तरह का उत्तर है जैसे "फाइलें बंद करने का क्या फायदा है, क्योंकि मेरे कार्यक्रम के बाहर निकलने पर अजगर और ओएस मेरे लिए अपनी फाइल बंद कर देंगे?"

यह बस अच्छी प्रोग्रामिंग की बात है। आपको कोड में इस बिंदु पर अपने थ्रेड्स शामिल करने चाहिए () जो कि थ्रेड अब नहीं चल रहा है, या तो क्योंकि आपको सकारात्मक रूप से यह सुनिश्चित करना है कि थ्रेड आपके ही कोड के साथ हस्तक्षेप करने के लिए नहीं चल रहा है, या कि आप सही तरीके से व्यवहार करना चाहते हैं बड़ी प्रणाली।

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

प्रदर्शन कारणों से जुड़ने () में शामिल नहीं होने का कोई कारण नहीं है, और मैं तर्क दूंगा कि आपके कोड को वह अच्छा प्रदर्शन करने की आवश्यकता नहीं है ।


6
धागे की सफाई के बारे में आप जो कहते हैं वह सच नहीं है। थ्रेडिंग के स्रोत कोड पर एक नज़र डालें। Tread.join ()। वह सभी कार्य करता है जो एक लॉक पर प्रतीक्षा करता है, और फिर वापस लौटता है। वास्तव में कुछ भी साफ नहीं किया जाता है।
Collin

1
@ कोल्लिन - धागा अपने आप में संसाधन हो सकता है, उस स्थिति में दुभाषिया और OS को वास्तव में "cruft" को साफ करने की आवश्यकता होगी।
qneill

1
फिर, सूत्रण के स्रोत कोड को देखें। Thread.join ()। वहाँ कुछ भी नहीं है जो संसाधनों के संग्रह को ट्रिगर करता है।
Collin

यह जरूरी नहीं है (और जैसा कि आप कहते हैं, बिल्कुल नहीं) थ्रेडिंग मॉड्यूल जो संसाधनों को पकड़ रहा है, लेकिन स्वयं धागा। ज्वाइन () का उपयोग करने का अर्थ है कि आप थ्रेड के लिए प्रतीक्षा कर रहे हैं कि वह क्या करना चाहता है, जिसमें संसाधनों का आवंटन और विमोचन शामिल हो सकता है।
क्रिस कोगडन 18

2
जब आप थ्रेड द्वारा रखे गए संसाधन जारी होते हैं तो आप प्रतीक्षा करते हैं या प्रभावित नहीं करते हैं। मुझे यकीन नहीं है कि आप इसे कॉलिंग के साथ क्यों बांध रहे हैं join()
कॉलिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.