Python中的生产者与消费者 实现多线程

来源:互联网 发布:js获得窗口宽度 编辑:程序博客网 时间:2024/05/21 20:21

   生产者与消费者问题是典型的同步问题。这里简单介绍两种不同的实现方法。

1,  条件变量

[python] view plain copy
  1. import threading  
  2.   
  3. import time  
  4.   
  5. class Producer(threading.Thread):  
  6.   
  7.     def __init__(self, t_name):  
  8.   
  9.         threading.Thread.__init__(self, name=t_name)  
  10.   
  11.    
  12.   
  13.     def run(self):  
  14.   
  15.         global x  
  16.   
  17.         con.acquire()  
  18.   
  19.         if x > 0:  
  20.   
  21.             con.wait()  
  22.   
  23.         else:  
  24.   
  25.             for i in range(5):  
  26.   
  27.                 x=x+1  
  28.   
  29.                 print "producing..." + str(x)  
  30.   
  31.             con.notify()  
  32.   
  33.         print x  
  34.   
  35.         con.release()  
  36.   
  37.    
  38.   
  39. class Consumer(threading.Thread):  
  40.   
  41.     def __init__(self, t_name):  
  42.   
  43.         threading.Thread.__init__(self, name=t_name)  
  44.   
  45.     def run(self):  
  46.   
  47.         global x  
  48.   
  49.         con.acquire()  
  50.   
  51.         if x == 0:  
  52.   
  53.             print 'consumer wait1'  
  54.   
  55.             con.wait()  
  56.   
  57.         else:  
  58.   
  59.             for i in range(5):  
  60.   
  61.                 x=x-1  
  62.   
  63.                 print "consuming..." + str(x)  
  64.   
  65.             con.notify()  
  66.   
  67.         print x  
  68.   
  69.         con.release()  
  70.   
  71.    
  72.   
  73. con = threading.Condition()  
  74.   
  75. x=0  
  76.   
  77. print 'start consumer'  
  78.   
  79. c=Consumer('consumer')  
  80.   
  81. print 'start producer'  
  82.   
  83. p=Producer('producer')  
  84.   
  85.    
  86.   
  87. p.start()  
  88.   
  89. c.start()  
  90.   
  91. p.join()  
  92.   
  93. c.join()  
  94.   
  95. print x  
  

    上面的例子中,在初始状态下,Consumer处于wait状态,Producer连续生产(对x执行增1操作)5次后,notify正在等待的Consumer。Consumer被唤醒开始消费(对x执行减1操作)

2,  同步队列

Python中的Queue对象也提供了对线程同步的支持。使用Queue对象可以实现多个生产者和多个消费者形成的FIFO的队列。

生产者将数据依次存入队列,消费者依次从队列中取出数据。

[python] view plain copy
  1. # producer_consumer_queue  
  2.   
  3. from Queue import Queue  
  4.   
  5. import random  
  6.   
  7. import threading  
  8.   
  9. import time  
  10.   
  11.    
  12.   
  13. #Producer thread  
  14.   
  15. class Producer(threading.Thread):  
  16.   
  17.     def __init__(self, t_name, queue):  
  18.   
  19.         threading.Thread.__init__(self, name=t_name)  
  20.   
  21.         self.data=queue  
  22.   
  23.     def run(self):  
  24.   
  25.         for i in range(5):  
  26.   
  27.             print "%s: %s is producing %d to the queue!/n" %(time.ctime(), self.getName(), i)  
  28.   
  29.             self.data.put(i)  
  30.   
  31.             time.sleep(random.randrange(10)/5)  
  32.   
  33.         print "%s: %s finished!" %(time.ctime(), self.getName())  
  34.   
  35.    
  36.   
  37. #Consumer thread  
  38.   
  39. class Consumer(threading.Thread):  
  40.   
  41.     def __init__(self, t_name, queue):  
  42.   
  43.         threading.Thread.__init__(self, name=t_name)  
  44.   
  45.         self.data=queue  
  46.   
  47.     def run(self):  
  48.   
  49.         for i in range(5):  
  50.   
  51.             val = self.data.get()  
  52.   
  53.             print "%s: %s is consuming. %d in the queue is consumed!/n" %(time.ctime(), self.getName(), val)  
  54.   
  55.             time.sleep(random.randrange(10))  
  56.   
  57.         print "%s: %s finished!" %(time.ctime(), self.getName())  
  58.   
  59.    
  60.   
  61. #Main thread  
  62.   
  63. def main():  
  64.   
  65.     queue = Queue()  
  66.   
  67.     producer = Producer('Pro.', queue)  
  68.   
  69.     consumer = Consumer('Con.', queue)  
  70.   
  71.     producer.start()  
  72.   
  73.     consumer.start()  
  74.   
  75.     producer.join()  
  76.   
  77.     consumer.join()  
  78.   
  79.     print 'All threads terminate!'  
  80.   
  81.    
  82.   
  83. if __name__ == '__main__':  
  84.   
  85.     main()  

在上面的例子中,Producer在随机的时间内生产一个“产品”,放入队列中。Consumer发现队列中有了“产品”,就去消费它。本例中,由于Producer生产的速度快于Consumer消费的速度,所以往往Producer生产好几个“产品”后,Consumer才消费一个产品。

Queue模块实现了一个支持多producer和多consumer的FIFO队列。当共享信息需要安全的在多线程之间交换时,Queue非常有用。Queue的默认长度是无限的,但是可以设置其构造函数的maxsize参数来设定其长度。Queue的put方法在队尾插入,该方法的原型是:

put( item[, block[, timeout]])

如果可选参数block为true并且timeout为None(缺省值),线程被block,直到队列空出一个数据单元。如果timeout大于0,在timeout的时间内,仍然没有可用的数据单元,Full exception被抛出。反之,如果block参数为false(忽略timeout参数),item被立即加入到空闲数据单元中,如果没有空闲数据单元,Full exception被抛出。

Queue的get方法是从队首取数据,其参数和put方法一样。如果block参数为true且timeout为None(缺省值),线程被block,直到队列中有数据。如果timeout大于0,在timeout时间内,仍然没有可取数据,Empty exception被抛出。反之,如果block参数为false(忽略timeout参数),队列中的数据被立即取出。如果此时没有可取数据,Empty exception也会被抛出。

原创粉丝点击