2013-04-17 63 views
0

我已經在python中編寫了一個生產者線程,並且我希望在設置某個事件時停止它的執行。我不知道如何使用threading.Event這個舉措。所以,我自己寫了一些代碼: -在python生產者線程中刪除shouldStop變量的使用

我已經使用了一個默認設置爲False的self.shouldStop變量。每當我想停止生產者線程的執行,我設置p.shouldStop爲True

import Queue 
import threading 
import time 

class ProducerThread(threading.Thread): 
    def __init__(self, q): 
     super(ProducerThread, self).__init__() 

     self._q = q 
     self.shouldStop = False 
    def run(self): 
     for i in range(5): 
      if self.shouldStop is True: 
       return 
      self._q.put(i) 

class ConsumerThread(threading.Thread): 
    def __init__(self, q): 
     super(ConsumerThread, self).__init__() 
     self._q = q 

    def run(self): 
     while True: 
      data = self._q.get() 
      if data == 'Stop': 
       print 'returning from the thread as I got %s message' % data 
       return 
      print "%s got %s. Sleeping for %s seconds. %s" % (self.getName(), data, data, time.time()) 
      time.sleep(data) 
      print "%s woke up from sleep after %s seconds %s" % (self.getName(), data, time.time()) 
    def stop(self): 
     self._q.put("Stop") 
if __name__ == '__main__': 
    q = Queue.Queue(1) 
    p = ProducerThread(q) 
    t = ConsumerThread(q) 
    p.start() 
    t.start() 
    p.shouldStop = True 
    p.join() 
    t.stop() 
    t.join() 

我的問題是:

是否存在被刪除使用shouldStop和使用threading.Event實現這一目標的任何更好的辦法?

回答

1

您必須在所有線程中共享相同的事件對象(就像您已經對隊列所做的那樣)。

然後用is_set()檢查是否設置了事件。 您也可以使用wait()(帶有超時)並捕獲超時錯誤以查明事件是否已設置。 我找到is_set()更容易閱讀的解決方案,所以這就是下面貼:

import Queue 
import threading 
import time 

class ProducerThread(threading.Thread): 

    def __init__(self, work_queue, shutdown_event): 
     super(ProducerThread, self).__init__() 

     self._work_queue  = work_queue 
     self._shutdown_event = shutdown_event 

    def run(self): 
     for i in range(5): 
      if self._shutdown_event.is_set(): 
       return 
      else: 
       self._work_queue.put(i) 

class ConsumerThread(threading.Thread): 

    def __init__(self, work_queue, shutdown_event): 
     super(ConsumerThread, self).__init__() 
     self._work_queue  = work_queue 
     self._shutdown_event = shutdown_event 

    def run(self): 
     while True: 
      try: 
       data = self._work_queue.get(timeout=1) 
      except Queue.Empty: 
       if self._shutdown_event.is_set(): 
        print 'returning from thread; queue is empty and ' \ 
          'shutdown_event.is_set() is True' 
        return 
       else: 
        continue 
      if self._shutdown_event.is_set(): 
       print 'returning from thread; shutdown_event.is_set() is True' 
       return 
      else: 
       print "%s got %s. Sleeping for %s seconds. %s" % (
        self.getName(), data, data, time.time()) 
       time.sleep(1.0+data/10) 
       print "%s woke up from sleep after %s seconds %s" % (
        self.getName(), str(1.0+data/10), time.time()) 


if __name__ == '__main__': 
    work_queue = Queue.Queue(maxsize = 1) 
    shutdown_event = threading.Event() 
    producer = ProducerThread(work_queue, shutdown_event) 
    consumer = ConsumerThread(work_queue, shutdown_event) 
    producer.start() 
    consumer.start() 
    p 
    time.sleep(10) 
    print 'MainThread: calling shutdown_event.set()' 
    shutdown_event.set() 
    producer.join() 
    consumer.join() 
+0

在消費者線程,Shoudnt了'GET'在'else'部分發生。這是因爲如果Producer的'​​put'完成了,但Consumer中的get'仍然在等待隊列中的某些數據。在這種情況下,該事件將永遠不會到達消費者。我對麼? – GodMan

+0

這是正確的,但將'get'移到'else'不會解決問題。假設你將'get'移動到'else':現在'producer'已經完成,但'shutdown_event'還沒有設置:消費者'如果self._shutdown_event.is_set()'會評估爲'False',那麼將會執行'else'並且消費者線程會阻止對'_work_queue.get()'的調用。 –

+1

正確的解決方法是在超時錯誤的情況下調用帶有超時的'get'並檢查事件狀態。 –

相關問題