生产者消费者 python_python中正确的生产者和消费者问题

假设有一个公共队列,生产者向队列中写数据,消费者从队列中读数据。当队列中没有任何数据的时候,消费者应该停止运行并等待(wait),而不是继续尝试读取数据而引发读取空队列的异常。而当生产者在队列中加入数据之后,应该有一个渠道去告诉(notify)消费者。然后消费者可以再次从队列中进行读取,而IndexError不再出现。

消费者:

from threading import Condition

condition = Condition()

class ConsumerThread(Thread):

def run(self):

global queue

while True:

condition.acquire()

if not queue:

print "Nothing in queue, consumer is waiting"

condition.wait()

print "Producer added something to queue and notified the consumer"

num = queue.pop(0)

print "Consumed", num

condition.release()

time.sleep(random.random())

生产者:

class ProducerThread(Thread):

def run(self):

nums = range(5)

global queue

while True:

condition.acquire()

num = random.choice(nums)

queue.append(num)

print "Produced", num

condition.notify()

condition.release()

time.sleep(random.random())

输出:

Produced 3

Consumed 3

Produced 1

Consumed 1

Produced 4

Consumed 4

Produced 3

Consumed 3

Nothing in queue, consumer is waiting

Produced 2

Producer added something to queue and notified the consumer

Consumed 2

Nothing in queue, consumer is waiting

Produced 2

Producer added something to queue and notified the consumer

Consumed 2

Nothing in queue, consumer is waiting

Produced 3

Producer added something to queue and notified the consumer

Consumed 3

Produced 4

Consumed 4

Produced 1

Consumed 1

解释:

对于消费者,在消费前检查队列是否为空。

如果为空,调用condition实例的wait()方法。

消费者进入wait(),同时释放所持有的lock。

除非被notify,否则它不会运行。

生产者可以acquire这个lock,因为它已经被消费者release。

当调用了condition的notify()方法后,消费者被唤醒,但唤醒不意味着它可以开始运行。

notify()并不释放lock,调用notify()后,lock依然被生产者所持有。

生产者通过condition.release()显式释放lock。

消费者再次开始运行,现在它可以得到队列中的数据而不会出现IndexError异常。

为队列增加大小限制

生产者不能向一个满队列继续加入数据。

它可以用以下方式来实现:

在加入数据前,生产者检查队列是否为满。

如果不为满,生产者可以继续正常流程。

如果为满,生产者必须等待,调用condition实例的wait()。

消费者可以运行。消费者消耗队列,并产生一个空余位置。

然后消费者notify生产者。

当消费者释放lock,消费者可以acquire这个lock然后往队列中加入数据。 最终版本如下:

from threading import Thread, Condition

import time

import random

queue = []

MAX_NUM = 10

condition = Condition()

class ProducerThread(Thread):

def run(self):

nums = range(5)

global queue

while True:

condition.acquire()

if len(queue) == MAX_NUM:

print "Queue full, producer is waiting"

condition.wait()

print "Space in queue, Consumer notified the producer"

num = random.choice(nums)

queue.append(num)

print "Produced", num

condition.notify()

condition.release()

time.sleep(random.random())

class ConsumerThread(Thread):

def run(self):

global queue

while True:

condition.acquire()

if not queue:

print "Nothing in queue, consumer is waiting"

condition.wait()

print "Producer added something to queue and notified the consumer"

num = queue.pop(0)

print "Consumed", num

condition.notify()

condition.release()

time.sleep(random.random())

ProducerThread().start()

ConsumerThread().start() 输出结果:

Produced 0

Consumed 0

Produced 0

Produced 4

Consumed 0

Consumed 4

Nothing in queue, consumer is waiting

Produced 4

Producer added something to queue and notified the consumer

Consumed 4

Produced 3

Produced 2

Consumed 3

Queue封装了Condition的行为,如wait(),notify(),acquire()。

利用Queue可以很方便的实现以上功能:

from threading import Thread

import time

import random

from Queue import Queue

queue = Queue(10)

class ProducerThread(Thread):

def run(self):

nums = range(5)

global queue

while True:

num = random.choice(nums)

queue.put(num)

print "Produced", num

time.sleep(random.random())

class ConsumerThread(Thread):

def run(self):

global queue

while True:

num = queue.get()

queue.task_done()

print "Consumed", num

time.sleep(random.random())

ProducerThread().start()

ConsumerThread().start()

解释:

在原来使用list的位置,改为使用Queue实例(下称队列)。

这个队列有一个condition,它有自己的lock。如果你使用Queue,你不需要为condition和lock而烦恼。

生产者调用队列的put方法来插入数据。

put()在插入数据前有一个获取lock的逻辑。

同时,put()也会检查队列是否已满。如果已满,它会在内部调用wait(),生产者开始等待。

消费者使用get方法。

get()从队列中移出数据前会获取lock。

get()会检查队列是否为空,如果为空,消费者进入等待状态。

get()和put()都有适当的notify()。现在就去看Queue的源码吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值