2013-07-10 4 views
12

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

दरअसल, मुझे एक दूसरे के खिलाफ सत्यापित करने के लिए पहले दो धागे वापस लौटने की प्रतीक्षा करनी होगी। लेकिन मुझे लगता है कि अगर मुझे पता है कि सबसे तेज़ इंतजार कैसे करें। मैं समझ सकता हूं कि दूसरे सबसे तेज़ इंतजार कैसे करें।

join(timeout) के बारे में बहुत कुछ बात करते हैं, लेकिन आप पहले से नहीं जानते कि कौन से इंतजार कर रहे हैं (कौन सा join अग्रिम में लागू करेगा)।

उत्तर

1

आप इसके लिए एक कार्यक्रम का उपयोग कर सकते हैं। देखें http://docs.python.org/2/library/threading.html#event-objects विचार यह है कि कार्यकर्ता थ्रेड समाप्त होने पर एक ईवेंट बढ़ाते हैं। जारी रखने से पहले मुख्य धागा इस घटना के लिए इंतजार कर रहा है। कार्यकर्ता धागा घटना के साथ स्वयं को पहचानने के लिए एक (mutexed) चर सेट कर सकता है।

1

या केवल एक सूची में सभी तैयार धागे का ट्रैक रखें और दूसरे थ्रेड को पूरा करने के लिए जो कुछ भी किया जाना है उसे पूरा करने दें, पायथन सूची थ्रेडसेफ हैं।

finished_threads = [] 
event = threading.Event() 

def func(): 
    do_important_stuff() 

    thisthread = threading.current_thread() 
    finished_threads.append(thisthread) 
    if len(finished_threads) > 1 and finished_threads[1] == thisthread: 
     #yay we are number two! 
     event.set() 

for i in range(5): 
    threading.Thread(target=func).start() 

event.wait() 
+0

यह मुख्य थ्रेड दो धागे जब तक इंतजार कर के बारे में थोड़ा और उत्तर नहीं मिलता है पूरा और फिर जारी कर रहे हैं: इसके बजाय आप पूरा करने के लिए जो नहीं हो सकता है क्या चाहता है दूसरा धागा पर सभी शेष गतिविधि हस्तांतरित की है। – Duncan

+1

सच; handle_two_threads_done() को इसके बजाय एक ईवेंट पर सेट करना चाहिए। संपादित। –

+0

उम्मम, पायथन सूची थ्रेडसेफ हैं? वास्तव में? मैंने सोचा था कि थ्रेड कोहेन्सी के लिए एक कतार() का उपयोग करने की आवश्यकता है! –

3

आप अपने धागे में प्रसंस्करण पाश किसी प्रकार का है, तो निम्न कोड उन्हें समाप्त होगा जब एक एक threading.Event() का उपयोग करके समाप्त हो जाता है:

def my_thread(stop_event): 
    while not stop_event.is_set(): 
     # do stuff in a loop 

     # some check if stuff is complete 
     if stuff_complete: 
      stop_event.set() 
      break 

def run_threads(): 
    # create a thread event 
    a_stop_event = threading.Event() 

    # spawn the threads 
    for x in range(5): 
     t = threading.Thread(target=my_thread, args=[a_stop_event]) 
     t.start() 

    while not a_stop_event.is_set(): 
     # wait for an event 
     time.sleep(0.1) 

    print "At least one thread is done" 

यदि आपका प्रक्रिया "सस्ते" एक भी है या अनुरोध-प्रतिक्रिया प्रकार धागा (यानी उदाहरण के लिए एक async HTTP अनुरोध) तो Duncan's answer एक अच्छा दृष्टिकोण है।

13

एक कतार का उपयोग करें: प्रत्येक थ्रेड जब पूरा कतार पर परिणाम रखता है और फिर तुम सिर्फ परिणाम की उपयुक्त संख्या पढ़ सकते हैं और शेष को अनदेखा करने की जरूरत है:

Queue.get() के लिए
#!python3.3 
import queue # For Python 2.x use 'import Queue as queue' 
import threading, time, random 

def func(id, result_queue): 
    print("Thread", id) 
    time.sleep(random.random() * 5) 
    result_queue.put((id, 'done')) 

def main(): 
    q = queue.Queue() 
    threads = [ threading.Thread(target=func, args=(i, q)) for i in range(5) ] 
    for th in threads: 
     th.daemon = True 
     th.start() 

    result1 = q.get() 
    result2 = q.get() 

    print("Second result: {}".format(result2)) 

if __name__=='__main__': 
    main() 

प्रलेखन (कोई तर्क के साथ यह Queue.get(True, None) के बराबर है:

Queue.get ([ब्लॉक [, टाइमआउट]])

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

+1

यदि आप 'q.get()' करते हैं तो कतार खाली होने पर यह 'खाली' अपवाद नहीं उठाएगा? – Michael

+2

@ माइकल, 'q.get()' के लिए डिफ़ॉल्ट है अवरुद्ध करने के लिए, इसलिए कोई अपवाद नहीं फेंक देगा, इसके परिणामस्वरूप यह मुख्य धागे को तब तक अवरुद्ध कर देगा जब तक परिणाम उपलब्ध न हो जाए। – Duncan

1

डंकन की विधि शायद सबसे अच्छी है और मैं इसकी सिफारिश करता हूं। मैं पहले "पूरा पूरा धागा पूरा करने के लिए प्रतीक्षा करें" की कमी से हल्के से नाराज हो गया हूं, हालांकि, मैंने इसे अभी कोशिश करने के लिए लिखा है। काम करने लगता है। threading.thread के स्थान पर बस MWThread का उपयोग करें और आपको यह नया wait_for_thread फ़ंक्शन मिलता है।

वैश्विक चर थोड़ा सा कर्कश हैं; एक विकल्प उन्हें कक्षा-स्तर चर बनाने के लिए होगा। लेकिन अगर यह किसी मॉड्यूल में छिपा हुआ है (mwthread.py या जो भी हो) तो यह किसी भी तरह से ठीक होना चाहिए।

#! /usr/bin/env python 

# Example of how to "wait for"/join whichever threads is/are done, 
# in (more or less) the order they're done. 

import threading 
from collections import deque 

_monitored_threads = [] 
_exited_threads = deque() 
_lock = threading.Lock() 
_cond = threading.Condition(_lock) 

class MWThread(threading.Thread): 
    """ 
    multi-wait-able thread, or monitored-wait-able thread 
    """ 
    def run(self): 
     tid = threading.current_thread() 
     try: 
      with _lock: 
       _monitored_threads.append(tid) 
      super(MWThread, self).run() 
     finally: 
      with _lock: 
       _monitored_threads.remove(tid) 
       _exited_threads.append(tid) 
       _cond.notifyAll() 

def wait_for_thread(timeout=None): 
    """ 
    Wait for some thread(s) to have finished, with optional 
    timeout. Return the first finished thread instance (which 
    is removed from the finished-threads queue). 

    If there are no unfinished threads this returns None 
    without waiting. 
    """ 
    with _cond: 
     if not _exited_threads and _monitored_threads: 
      _cond.wait(timeout) 
     if _exited_threads: 
      result = _exited_threads.popleft() 
     else: 
      result = None 
    return result 

def main(): 
    print 'testing this stuff' 
    def func(i): 
     import time, random 
     sleeptime = (random.random() * 2) + 1 
     print 'thread', i, 'starting - sleep for', sleeptime 
     time.sleep(sleeptime) 
     print 'thread', i, 'finished' 

    threads = [MWThread(target=func, args=(i,)) for i in range(3)] 
    for th in threads: 
     th.start() 
    i = 0 
    while i < 3: 
     print 'main: wait up to .5 sec' 
     th = wait_for_thread(.5) 
     if th: 
      print 'main: got', th 
      th.join() 
      i += 1 
     else: 
      print 'main: timeout' 
    print 'I think I collected them all' 
    print 'result of wait_for_thread():' 
    print wait_for_thread() 

if __name__ == '__main__': 
    main()