我听说协程的.Select
版本最终将在Python中弃用(也许在3.8之后),并且仅支持@asyncio.coroutine
。今天,我使用装饰器版本是为了能够async def
(而不是yield
另一个协程),因为我正在等待某些更改(例如在yield from
循环内轮询)或将大部分耗时的阻塞代码分成较小的块(从而改善并发体验)。
这是一个最小的示例:
while
这将打印以下内容:
import asyncio
@asyncio.coroutine
def foo(l):
print('entering foo')
while l[0] == 0:
yield
print('leaving foo')
async def bar(l):
print('entering bar')
await asyncio.sleep(1)
l[0] = 1
await asyncio.sleep(1)
print('leaving bar')
async def main():
l = [0]
t0 = asyncio.ensure_future(foo(l))
t1 = asyncio.ensure_future(bar(l))
await t0
await t1
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
如何在entering foo
entering bar
# foo is polling
# 1 second elapses
leaving foo
# 1 second elapses
leaving bar
版的协程中实现这一目标?我们应该使用async def
吗?
答案 0 :(得分:4)
await asyncio.sleep(0)
可以用来做您想做的事,但是在当前情况下,这不是一个好的解决方案。事件循环在执行的每个“滴答滴答”中都需要返回foo
:这会浪费CPU资源。
当您要等待协程内部发生某些事情时,正确的方法是使用asyncio.Event:
async def foo(event):
print('entering foo')
await event.wait()
print('leaving foo')
async def bar(event):
print('entering bar')
await asyncio.sleep(1)
event.set()
await asyncio.sleep(1)
print('leaving bar')
async def main():
event = asyncio.Event()
t0 = asyncio.ensure_future(foo(event))
t1 = asyncio.ensure_future(bar(event))
await t0
await t1
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
这样,事件循环将只返回一次:foo
实际上已经被设置。
答案 1 :(得分:1)
是的,我认为await asyncio.sleep(0)
是这样做的正确方法,请参见https://github.com/python/asyncio/issues/284。因此foo
变为:
async def foo(l):
print('entering foo')
while l[0] == 0:
await asyncio.sleep(0)
print('leaving foo')