asyncio
模块来正确地实现两个并发运行的Task
对象。简而言之,asyncio似乎是设计用于处理事件循环中异步进程和并发
Task
执行的。它推广了await
(在async函数中应用)作为一种无回调等待和使用结果的方式,而无需阻塞事件循环。(Futures和回调仍然是可行的替代方案)。它还提供了
asyncio.Task()
类,这是Future的一个特殊子类,旨在包装协程。最好使用asyncio.ensure_future()
方法来调用它。asyncio任务的预期用途是允许独立运行的任务在同一事件循环中与其他任务“并发”运行。我的理解是,Tasks
与事件循环连接,然后自动在await
语句之间驱动协程。我很喜欢能够使用并发任务而无需使用
Executor
类之一的想法,但我没有找到太多有关实现的详细信息。这是我目前的做法:
import asyncio
print('running async test')
async def say_boo():
i = 0
while True:
await asyncio.sleep(0)
print('...boo {0}'.format(i))
i += 1
async def say_baa():
i = 0
while True:
await asyncio.sleep(0)
print('...baa {0}'.format(i))
i += 1
# wrap in Task object
# -> automatically attaches to event loop and executes
boo = asyncio.ensure_future(say_boo())
baa = asyncio.ensure_future(say_baa())
loop = asyncio.get_event_loop()
loop.run_forever()
在尝试同时运行两个循环任务的情况下,我发现除非任务有内部
await
表达式,否则它将在while
循环中卡住,有效地阻塞其他任务的运行(就像普通的while
循环一样)。然而,一旦任务必须等待,它们似乎可以并发运行而没有问题。因此,
await
语句似乎为事件循环提供了一个支点,以便在任务之间进行切换,从而产生并发效果。带有内部
await
的示例输出:running async test
...boo 0
...baa 0
...boo 1
...baa 1
...boo 2
...baa 2
没有内部await
的示例输出:
...boo 0
...boo 1
...boo 2
...boo 3
...boo 4
问题
这个实现是否是使用 asyncio
进行并发循环任务的“正确”示例?
唯一的方式是让 Task
提供一个阻塞点(await
表达式),以便事件循环可以处理多个任务,这是正确的吗?
编辑
2022年更新:请注意,自此问题提出以来,asyncio
API 已经发生了相当大的变化。请参见新标记为正确答案的答案,该答案现在显示了在 Python 3.10 中给出的 API 的正确使用方式。我仍然建议从 @dano 的答案中获取更广泛的了解。
yield from
到下一个yield from
期间原子化地执行自己。 - Andrew Svetlov