同步调用协同程序

Max*_*Tet 10 python-3.x python-asyncio

想象一下以下非常常见的情况:您编写了一个冗长而复杂的函数,并意识到应该将一些代码提取到一个单独的函数中以便重用和/或可读.通常,这个额外的函数调用不会改变程序的语义.

但是,现在假设您的函数是一个协程,并且您要提取的代码包含至少一个异步调用.将它提取到一个单独的函数现在突然改变你的程序语义,方法是插入一个新的协同程序产生的点,事件循环控制,并且可以在其间安排任何其他协程.

以前的例子:

async def complicated_func():
    foo()
    bar()
    await baz()
Run Code Online (Sandbox Code Playgroud)

示例之后:

async def complicated_func():
    foo()
    await extracted_func()

async def extracted_func():
    bar()
    await baz()
Run Code Online (Sandbox Code Playgroud)

在之前的示例中,complicated_func保证不会在呼叫foo()和呼叫之间暂停bar().重构后,此保证将丢失.

我的问题是:是否有可能调用extracted_func()它立即执行,好像它的代码是内联的?或者是否有其他方法可以在不更改程序语义的情况下执行此类常见的重构任务?

Vin*_*ent 9

重构后,此保证将丢失.

实际上并非如此.

是否可以调用extracted_func()使其立即执行,就像它的代码是内联的一样?

情况已经如此.

await some_coroutine()意味着some_coroutine可能会将控制权交还给事件循环,但在实际等待未来(例如某些I/O操作)之前,它不会这样做.

考虑这个例子:

import asyncio

async def coro():
    print(1)
    await asyncio.sleep(0)
    print(3)

async def main():
    loop.call_soon(print, 2)
    await coro()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)

注意如何2在预期之间13预期之间打印.

这也意味着可以通过编写这样的代码来冻结事件循环:

async def coro():
    return

async def main():
    while True:
        await coro()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,事件循环永远不会有机会运行另一个任务.

  • 没错,eventloop可以控制,如果你正在等待一些可以等待的事情,像@Vincent这样的异步提到了i/o操作,线程/进程执行器,超时(asyncio.sleep)...更多'await'没有神奇地使一个函数成为异步或非阻塞. (4认同)
  • 我不完全了解。我给人的印象是,调用`await some_coroutine()`会隐式创建一个Future(或任务),将其排队到事件循环中,并屈服于事件循环,以便它可以自行决定调用下一个可用任务。现在,您是否在说实际上不是这种情况,而是立即调用some_coroutine()而不涉及事件循环? (3认同)
  • @MaxTet`现在,您是说不是这种情况,而是不涉及事件循环就立即调用some_coroutine()吗?这正是发生的情况。您在评论的第一部分中描述的是“ await asyncio.ensure_future(coro())”。 (2认同)