What is the difference between @types.coroutine and @asyncio.coroutine decorators?

寵の児 提交于 2019-11-27 18:50:41

The difference is if you have a yield statement or not. Here's the code:

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())

In this example everything seem same - here's the debugging info from pycharm (we're standing on the "Going down!" line). Nothing is printed in console yet, so the functions didn't start yet.

But if we remove the yield, the types version will start function instantly!

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())

Now we have doing something in types in console printed. And here's the debug info:

As you can see it starts right after call, if there is no result and returns None.


As for usage, you should use asyncio version always. If you need to run it like fire and forget (running instantly and getting results later) - use ensure_future function.

One other subtle difference: generator-based coroutines decorated with @asyncio.coroutine will test True for asyncio.iscoroutinefunction(), while those decorated with @types.coroutine will test 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))

Output:

(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

Nonetheless, both of these are awaitable.


*Note also that this difference does not apply to their _results: replace iscoroutinefunction() with iscoroutine() (which tests for a coroutine object), and old_coro_with_asyncio() + old_coro_with_types() will evaluate False for both.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!