asyncio.Queue一个队列,规则是先进先出,先存入先取出。
官方文档上有个例子:
https://asyncio.readthedocs.io/en/latest/producer_consumer.html
代码如下:
# -*- coding: UTF-8 -*-
#win7+python3.7
import asyncio
import random
async def produce(queue, n):
for x in range(n):
# produce an item
print('producing {}/{}'.format(x, n))
# simulate i/o operation using sleep
await asyncio.sleep(random.random())
item = str(x)
# put the item in the queue
await queue.put(item)
async def consume(queue):
while True:
# wait for an item from the producer
item = await queue.get()
# process the item
print('consuming {}...'.format(item))
# simulate i/o operation using sleep
await asyncio.sleep(random.random())
# Notify the queue that the item has been processed
queue.task_done()
async def run(n):
queue = asyncio.Queue()
# schedule the consumer,注意此时consume方法并没有真正开始运行
consumer = asyncio.ensure_future(consume(queue))
# run the producer and wait for completion,此时produce生产后,consume才开始运行
await produce(queue, n)
# wait until the consumer has processed all items
await queue.join()
# the consumer is still awaiting for an item, cancel it
consumer.cancel()
loop = asyncio.get_event_loop()
loop.run_until_complete(run(10))
loop.close()
上面程序不要在Spyder中运行,因为有些新特性好像还不支持。
程序通过produce方法把10个任务放入Queue中,通过consume方法进行消费回收,注释里面把每个方法的作用都说清楚了,不再解释。
在此,要想强调一下关于Queue.put_nowait方法,官方的解释是:
Put an item into the queue without blocking.
If no free slot is immediately available, raise
QueueFull
.
意思是将item放入无阻塞的queue中,如果没有可用的插槽(即没有存放空间),就抛出QueueFull异常。把上面的程序改一下:
import asyncio
import random
async def produce(queue, n):
for x in range(n):
# produce an item
print('producing {}/{}'.format(x, n))
# simulate i/o operation using sleep
await asyncio.sleep(random.random())
item = str(x)
#替换 await queue.put(item)
queue.put_nowait(item)
#打印当前queue里面item存放数量
print(queue.qsize())
async def run(n):
queue = asyncio.Queue(maxsize=3)
await produce(queue, n)
loop = asyncio.get_event_loop()
loop.run_until_complete(run(6))
loop.close()
我们将await put方法替换成了put_nowait方法,将Queue的容量设为3个,而生产的任务设为6个,运行结果如下:
可以看出,在生产第4个任务的时候,因为Queue的容量只有3个,所以抛出QueueFull错误,符合预期要求。
注意,上面的程序只使用了produce方法,没有调用consume方法,因为我们一边调用produce,一边调用consume时,consume方法会将完成的任务进行回收。相当于出水管将水抽出水池,而入水管又将水抽入,有可能永远也不会满(即抛出QueueFull异常)。