2013-04-17 32 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'并检查事件状态。 –

相关问题