【问题标题】:How do yield-based coroutines in Python differ from coroutines with @asyncio.coroutine and @types.coroutine decorators?Python 中基于 yield 的协程与带有 @asyncio.coroutine 和 @types.coroutine 装饰器的协程有何不同?
【发布时间】:2019-11-24 15:33:36
【问题描述】:

我一直在尝试理解异步编程,尤其是在 Python 中。我知道 asyncio 是建立在一个调度协程执行的事件循环之上的,但是我已经阅读了几种不同的方式来定义协程,我很困惑它们是如何相互关联的。

我阅读了this article 以了解有关该主题的更多背景信息。尽管它涵盖了我提到的四种类型的协程中的每一种,但它并没有完全描述它们之间的区别。无需任何外部模块,可以使用yield作为等号右侧的表达式创建协程,然后可以通过.send()输入数据。但是,使用@asyncio.coroutine@types.coroutine 装饰器的代码示例从不使用我发现的.send()。文章中的代码示例如下:

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

我的问题是:

  1. yield 协程与typesasyncio 修饰的协程有什么关系,.send() 功能在哪里使用?
  2. 装饰器为未装饰的基于生成器的协程添加了哪些功能?
  3. @asyncio.coroutine@types.coroutine 装饰器有何不同?我阅读this answer 试图理解这一点,但这里提到的唯一区别是types 协程在没有yield 语句的情况下像子程序一样执行。还有什么其他的吗?
  4. 这些基于生成器的协程在功能和实现上与最新的原生 async/await 协程有何不同?

【问题讨论】:

  • yield 旨在将值 out 发送到使用您的生成器的任何人。发送回生成器的内容完全取决于处理生成器的代码。在协程的情况下,您的生成器由某种事件循环处理(它为您调用 .send),并且您可以保证传递给生成器的值是直接从您传递的值产生的,因此为什么“ “等待”是协程的一个更直观的词。
  • @TadhgMcDonald-Jensen asyncio.coroutine 和 types.coroutine 装饰器在用途和功能上有何不同?
  • 我真的不知道是什么原因我没有发布答案,我会看看源代码,看看我是否能找到适合你的答案。
  • 在此处查看@asyncio.coroutine@types.coroutine 之间的重要区别:stackoverflow.com/a/49477233/2085626

标签: python asynchronous async-await generator coroutine


【解决方案1】:

你可能会笑,我看了source code for asyncio.coroutine,发现它使用types.coroutine(任何带有#!>的评论都是我添加的)

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

所以我认为这只能归结为历史问题,asyncio 存在的时间比types 要长,所以原始处理在这里完成,然后当类型出现时,真正的包装器被移到那里,asyncio 继续只有一些额外的包装材料。但归根结底,两者都只是模仿async def的行为

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 2019-06-03
    • 1970-01-01
    • 2021-06-15
    • 2015-12-11
    • 2015-05-12
    • 2019-07-09
    • 2017-10-28
    • 1970-01-01
    相关资源
    最近更新 更多