出于可读性原因,我可能会破坏代码。所以

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')之间运行代码,因此,对于某些算法,竞争条件更容易出现。
  • 产生事件循环
  • (大概)有一些开销

    因此,有没有一种方法可以在不产生事件循环的情况下调用协程以避免上述情况发生?

    最佳答案

    这个问题的前提是不正确的:与人们期望的相反,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()(如果选择暂停,则挂起),并假设前者可以leadbugs

    换句话说,分解后的代码实际上等同于重构之前的代码。在print('top')print('1')之间执行另一项任务的唯一方法是在它们之间添加新的await(实际上挂起了协程),但是对于原始代码也可以如此。



    存在开销,但是它可以与函数调用的开销相比,而不是与运行事件循环的迭代要大得多的开销。

    关于python - 调用协程而不产生事件循环,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55556474/

    10-12 21:04