【问题标题】:What is the difference between @types.coroutine and @asyncio.coroutine decorators?@types.coroutine 和 @asyncio.coroutine 装饰器有什么区别?
【发布时间】:2023-03-21 22:00:02
【问题描述】:

文档说:

@asyncio.coroutine

装饰器来标记基于生成器的协程。这使得生成器可以使用 yield from 来调用 async def 协程,并且 使生成器能够被 async def 协程调用,例如 使用 await 表达式的实例。

_

@types.coroutine(gen_func)

这个函数转换一个生成器 函数转换为协程函数,该函数返回基于生成器 协程。基于生成器的协程仍然是生成器 迭代器,但也被认为是一个协程对象,并且是 可以等待的。但是,它可能不一定实现__await__() 方法。

所以看起来目的是一样的——将生成器标记为协程(Python3.5 及更高版本中的async def对某些功能做了什么)。

什么时候需要asyncio.coroutine,什么时候需要types.coroutine,有什么区别?

【问题讨论】:

  • 查看代码差异很小,主要在于它们如何接受方法。 asyncio 是一个必须与早期 Python 版本兼容的代码库,而 types 仅与 Python 本身一起分发。因此,您可以将asyncio.coroutine() 视为types.coroutine() 的反向端口,可用于其他Python 版本。
  • 在最新的开发中,asyncio.coroutine 函数实际上是调用 types.coroutine(coro) 来包装结果

标签: python asynchronous python-3.5


【解决方案1】:

不同之处在于您是否有 yield 语句。 代码如下:

from types import coroutine as t_coroutine
from asyncio import coroutine as a_coroutine, ensure_future, sleep, get_event_loop


@a_coroutine
def a_sleep():
    print("doing something in async")
    yield 1


@t_coroutine
def t_sleep():
    print("doing something in types")
    yield 1


async def start():
    sleep_a = a_sleep()
    sleep_t = t_sleep()
    print("Going down!")


loop = get_event_loop()
loop.run_until_complete(start())

在这个例子中,一切看起来都一样——这是来自 pycharm 的调试信息(我们站在“Going down!”行)。控制台中尚未打印任何内容,因此功能尚未启动。

但是如果我们删除yieldtypes 版本将立即启动!

from types import coroutine as t_coroutine
from asyncio import coroutine as a_coroutine, ensure_future, sleep, get_event_loop


@a_coroutine
def a_sleep():
    print("doing something in async")


@t_coroutine
def t_sleep():
    print("doing something in types")


async def start():
    sleep_a = a_sleep()
    sleep_t = t_sleep()
    print("Going down!")


loop = get_event_loop()
loop.run_until_complete(start())

现在我们在控制台打印了doing something in types。这是调试信息:

如您所见它在调用后立即启动,如果没有结果并返回 None。


至于用法,您应该始终使用asyncio 版本。如果您需要像 fire and forget 一样运行它(立即运行并稍后获得结果)- 使用 ensure_future 函数。

【讨论】:

    【解决方案2】:

    另一个细微的区别:用@asyncio.coroutine 装饰的基于生成器的协程将测试True 以获得asyncio.iscoroutinefunction(),而用@types.coroutine 装饰的协程将测试False

    # testcoro.py
    import asyncio
    import inspect
    import types
    
    @asyncio.coroutine
    def old_coro_with_asyncio():
        yield from asyncio.sleep(1)
    
    @types.coroutine
    def old_coro_with_types():
        yield from asyncio.sleep(1)
    
    if __name__ == "__main__":
        for coro in (old_coro_with_asyncio, old_coro_with_types):
            print(coro.__name__, 'iscoroutine:', asyncio.iscoroutine(coro))
            print(coro.__name__, 'iscoroutinefunc:', asyncio.iscoroutinefunction(coro))
    

    输出:

    (py37) $ python3 testcoro.py 
    old_coro_with_asyncio iscoroutine: False
    old_coro_with_asyncio iscoroutinefunc: True
    old_coro_with_types iscoroutine: False
    old_coro_with_types iscoroutinefunc: False
    

    不过,这两个都是可以等待的。


    *还要注意,这种差异不适用于它们的 _results:将 iscoroutinefunction() 替换为 iscoroutine()(用于测试协程对象),old_coro_with_asyncio() + old_coro_with_types() 将评估两者的 False。

    【讨论】:

    • 但是inspect.iscoroutinefunction(old_coro_with_asyncio)返回False
    猜你喜欢
    • 2019-06-03
    • 2012-01-09
    • 2020-02-21
    • 2019-11-24
    • 2016-09-16
    • 2018-04-17
    • 2011-02-04
    • 2018-07-19
    • 2023-04-03
    相关资源
    最近更新 更多