出于可读性原因,我可能会破坏代码。所以
async coro_top():
print('top')
print('1')
# ... More asyncio code
print('2')
# ... More asyncio code
...变成类似
async coro_top():
print('top')
await coro_1()
await coro_2()
async coro_1()
print('1')
# ... More asyncio code
async coro_2()
print('2')
# ... More asyncio code
但是,额外的await
表示它们不是严格等价的
另一个并发任务可以在print('top')
和print('1')
之间运行代码,因此对于某些算法,竞态条件更容易出现。
(大概)产生事件循环的开销很小
为了避免上述情况,有没有一种方法可以在不产生事件循环的情况下调用协程?
答案 0 :(得分:3)
这个问题的前提是不正确的:与人们的期望相反,await
不是不会自动产生事件循环。您可以轻松地测试一下:
async def noop():
pass
async def busy_loop(msg):
while True:
print(msg)
await noop()
# keeps printing 'a', the event loop is stuck
asyncio.get_event_loop().run_until_complete(
asyncio.gather(busy_loop('a'), busy_loop('b')))
尽管busy_loop
一直在等待,但它仍然阻止事件循环,因此其他任务将无法运行,甚至无法取消。这是因为它等待的noop
协程永远不会中止执行。
await some_coroutine()
并不意味着“调度some_coroutine()
并屈服于事件循环,并在完成时恢复”。意思是“开始执行some_coroutine()
,并且如果/如果它选择暂停,则继续”,并假设前者可以lead至bugs。>
换句话说,分解的代码实际上等同于重构之前的代码。在print('top')
和print('1')
之间执行另一任务的唯一方法是在它们之间添加新的await
(实际上是暂停协程)。原始代码也是如此。
(大概)产生事件循环的开销很小
存在开销,但它与函数调用的开销相当,而不是与运行事件循环的迭代要大得多的开销。