python - ¿Cuál es la diferencia entre los decoradores @ types.coroutine y @ asyncio.coroutine?
asynchronous python-3.5 (2)
La diferencia es si tienes una declaración de rendimiento o no. Aquí está el código:
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())
En este ejemplo, todo parece igual: aquí está la información de depuración de pycharm (estamos parados en la línea "¡Bajando!"). Todavía no se imprime nada en la consola, por lo que las funciones aún no se han iniciado.
¡Pero si eliminamos el yield
, la versión de types
comenzará a funcionar instantáneamente!
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())
Ahora tenemos que doing something in types
en consola impresa. Y aquí está la información de depuración:
Como puede ver , comienza justo después de la llamada , si no hay un resultado y devuelve Ninguno.
En cuanto al uso, debes usar siempre la versión asyncio
. Si necesita ejecutarlo como disparar y olvidar (ejecutando instantáneamente y obteniendo resultados más adelante), use la función ensure_future
.
Las documentaciones dicen:
@ asyncio.coroutine
Decorador para marcar corutines basados en generadores. Esto permite que el generador use el rendimiento para llamar a las definiciones de sincronía, y también permite que el generador sea llamado por las definiciones de sincronía, por ejemplo, utilizando una expresión de espera.
_
@ types.coroutine (gen_func)
Esta función transforma una función de generador en una función de coroutine que devuelve un coroutine basado en generador. El coroutine basado en generador sigue siendo un iterador generador, pero también se considera que es un objeto coroutine y es esperable. Sin embargo, puede que no implemente necesariamente el
__await__()
.
Por lo tanto, parece que los propósitos son los mismos: marcar un generador como coroutine (lo que hace async def
en Python3.5 y superior con algunas características).
Cuando necesito usar asyncio.coroutine
cuando necesites usar types.coroutine
, ¿cuál es la diferencia?
Otra diferencia sutil: las coroutinas basadas en generadores decoradas con @asyncio.coroutine
probarán True
para asyncio.iscoroutinefunction()
, mientras que aquellas decoradas con @types.coroutine
probarán 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))
Salida:
(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
No obstante, ambos son aguardables.
* Tenga en cuenta también que esta diferencia no se aplica a sus _resultados: reemplace iscoroutinefunction()
con iscoroutine()
(que analiza un objeto de rutina), y old_coro_with_asyncio()
+ old_coro_with_types()
evaluará False para ambos.