【问题标题】:Calling a coroutine synchronously同步调用协程
【发布时间】:2017-07-03 09:53:49
【问题描述】:

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

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

之前的例子:

async def complicated_func():
    foo()
    bar()
    await baz()

之后的示例:

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

async def extracted_func():
    bar()
    await baz()

在前面的示例中,保证complicated_func 在调用foo() 和调用bar() 之间不会被挂起。重构之后,这个保证就失去了。

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

【问题讨论】:

    标签: python-3.x python-asyncio


    【解决方案1】:

    重构之后,这个保证就失去了。

    其实不然。

    是否可以调用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())
    

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

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

    async def coro():
        return
    
    async def main():
        while True:
            await coro()
    

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

    【讨论】:

    • 我不认为我完全理解。我的印象是调用await some_coroutine() 隐含地创建了一个未来(或一个任务),将其排入事件循环并屈服于事件循环,以便它可以自行决定调用下一个可用任务。现在,您是说实际上并非如此,而是立即调用some_coroutine(),而不涉及事件循环?
    • 没错,如果你在等待可以等待的东西,比如@Vincent提到的异步操作,线程/进程执行器,超时(asyncio.sleep),eventloop可以控制。 . 更多的'await'不会神奇地使函数成为异步或非阻塞的。
    • @MaxTet Now, are you saying that this is actually not the case and instead some_coroutine() is called right away, without involving the event loop? 这正是发生的事情。您在评论的第一部分中描述的是await asyncio.ensure_future(coro())
    • 好的,谢谢你解决这个问题。看来,我的假设是完全错误的。
    • 是否有文档来源来支持这一点?
    猜你喜欢
    • 2013-08-07
    • 2022-01-13
    • 2020-02-23
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多