问题
I have been trying to understand asynchronous programming, particularly in Python. I understand that asyncio is built off of an event loop which schedules the execution of coroutines, but I have read about several different ways to define coroutines, and I am confused how they all relate to each other.
I read this article for more background information on the topic. Although it covers each of the four types of coroutines I have mentioned, it does not entirely describe how they differ. Without any external modules, a coroutine can be created using yield
as an expression on the right side of an equals, and then data can be inputted through the .send()
. However, code examples using the @asyncio.coroutine
and @types.coroutine
decorators do not ever use .send()
from what I've found. Code examples from the article are below:
# Coroutine using yield as an expression
def coro():
hello = yield "Hello"
yield hello
c = coro()
print(next(c), end=" ")
print(c.send("World")) # Outputs Hello World
# Asyncio generator-based coroutine
@asyncio.coroutine
def display_date(num, loop):
end_time = loop.time() + 50.0
while True:
print("Loop: {} Time: {}".format(num, datetime.datetime.now()))
if (loop.time() + 1.0) >= end_time:
break
yield from asyncio.sleep(random.randint(0, 5))
# Types generator-based coroutine
@types.coroutine
def my_sleep_func():
yield from asyncio.sleep(random.randint(0, 5))
# Native coroutine in Python 3.5+
async def display_date(num, loop, ):
end_time = loop.time() + 50.0
while True:
print("Loop: {} Time: {}".format(num, datetime.datetime.now()))
if (loop.time() + 1.0) >= end_time:
break
await asyncio.sleep(random.randint(0, 5))
My questions are:
- How do the
yield
coroutines relate to thetypes
orasyncio
decorated coroutines, and where is the.send()
functionality utilized? - What functionality do the decorators add to the undecorated generator-based coroutine?
- How do the
@asyncio.coroutine
and@types.coroutine
decorators differ? I read this answer to try and understand this, but the only difference mentioned here is that thetypes
coroutine executes like a subroutine if it has no yield statement. Is there anything more to it? - How do these generator-based coroutines differ in functionality and in implementation from the latest native
async/await
coroutines?
回答1:
you will likely laugh, I took a look at the source code for asyncio.coroutine and found it uses types.coroutine
(any comment with #!>
is added by me)
def coroutine(func):
"""Decorator to mark coroutines...."""
#!> so clearly the async def is preferred.
warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
DeprecationWarning,
stacklevel=2)
if inspect.iscoroutinefunction(func):
#!> since 3.5 clearly this is returning something functionally identical to async def.
# In Python 3.5 that's all we need to do for coroutines
# defined with "async def".
return func
if inspect.isgeneratorfunction(func):
coro = func
else:
#!> omitted, makes a wrapper around a non generator function.
#!> USES types.coroutine !!!!
coro = types.coroutine(coro)
if not _DEBUG:
wrapper = coro
else:
#!> omitted, another wrapper for better error logging.
wrapper._is_coroutine = _is_coroutine # For iscoroutinefunction().
return wrapper
So I think this comes down to historical stuff only, asyncio
existed for longer than types
so the original handling was done here, then when types came along the true wrapper was moved there and asyncio continued to just have some extra wrapping stuff. But at the end of the day, both are just to mimic the behaviour of async def
来源:https://stackoverflow.com/questions/57048080/how-do-yield-based-coroutines-in-python-differ-from-coroutines-with-asyncio-cor