为什么等待queue.get()被阻止?
import asyncio
async def producer(queue, item):
await queue.put(item)
async def consumer(queue):
val = await queue.get()
print("val = %d" % val)
async def main():
queue = asyncio.Queue()
await consumer(queue)
await producer(queue, 1)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
如果我在 consumer()之前调用 producer(),则效果很好 也就是说,以下方法可以正常工作。
async def main():
queue = asyncio.Queue()
await producer(queue, 1)
await consumer(queue)
为什么不等待queue.get(),将控制权交还给事件循环,以便生产者协程可以运行,从而填充队列,以便queue.get()返回。 / p>
答案 0 :(得分:0)
这是因为您调用了await consumer(queue)
,这意味着直到procuder
返回之前,下一行(consumer
)才被调用,这当然不会发生,因为还没有人产生
在文档中查看示例,看看它们如何在其中使用:https://docs.python.org/3/library/asyncio-queue.html#examples
另一个简单的例子:
import asyncio
import random
async def produce(queue, n):
for x in range(1, n + 1):
# 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)
# indicate the producer is done
await queue.put(None)
async def consume(queue):
while True:
# wait for an item from the producer
item = await queue.get()
if item is None:
# the producer emits None to indicate that it is done
break
# process the item
print('consuming item {}...'.format(item))
# simulate i/o operation using sleep
await asyncio.sleep(random.random())
loop = asyncio.get_event_loop()
queue = asyncio.Queue(loop=loop)
producer_coro = produce(queue, 10)
consumer_coro = consume(queue)
loop.run_until_complete(asyncio.gather(producer_coro, consumer_coro))
loop.close()
答案 1 :(得分:0)
您应将.run_until_complete()
与.gather()
一起使用
这是您更新的代码:
import asyncio
async def producer(queue, item):
await queue.put(item)
async def consumer(queue):
val = await queue.get()
print("val = %d" % val)
queue = asyncio.Queue()
loop = asyncio.get_event_loop()
loop.run_until_complete(
asyncio.gather(consumer(queue), producer(queue, 1))
)
loop.close()
出局:
val = 1
您还可以将.run_forever()
与.create_task()
一起使用
因此您的代码段将是:
import asyncio
async def producer(queue, item):
await queue.put(item)
async def consumer(queue):
val = await queue.get()
print("val = %d" % val)
queue = asyncio.Queue()
loop = asyncio.get_event_loop()
loop.create_task(consumer(queue))
loop.create_task(producer(queue, 1))
try:
loop.run_forever()
except KeyboardInterrupt:
loop.close()
出局:
val = 1
答案 2 :(得分:0)
您需要同时启动消费者和生产者,例如像这样定义main
:
async def main():
queue = asyncio.Queue()
await asyncio.gather(consumer(queue), producer(queue, 1))
如果由于gather
和consumer
在不同的区域运行而无法使用producer
,那么您可以这样做(等效):
async def main():
queue = asyncio.Queue()
asyncio.create_task(consumer(queue))
asyncio.create_task(producer(queue, 1))
await asyncio.sleep(100) # what your program actually does
为什么
await queue.get()
不将控制权放回事件循环,以便生产者协程可以运行,从而填充队列,以便queue.get()
可以返回。
await queue.get()
正在将控制权交还给事件循环。但是 await 表示 wait ,因此,当您的main
协程说await consumer(queue)
时,这意味着“ consumer(queue)
完成后恢复我。 consumer(queue)
本身正在等待某人产生某些东西,您遇到了典型的死锁情况。
撤消订单仅因为您的生产者是一次性的,所以它立即返回给调用者。如果您的生产者正巧等待外部源(例如套接字),那么那里也会有死锁。无论如何编写producer
和consumer
,并行启动它们都可以避免死锁。