Python中基于收益的协程与@ asyncio.coroutine和@ types.coroutine装饰器的协程有何不同? [英] How do yield-based coroutines in Python differ from coroutines with @asyncio.coroutine and @types.coroutine decorators?

查看:189
本文介绍了Python中基于收益的协程与@ asyncio.coroutine和@ types.coroutine装饰器的协程有何不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试理解异步编程,尤其是在Python中.我了解到asyncio是基于事件循环构建的,该事件循环调度了协程的执行,但是我已经读到了几种定义协程的不同方法,而且我对它们之间如何相互关联感到困惑.

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.

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

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

我的问题是:

  1. yield协程与typesasyncio装饰的协程有何关系,.send()功能在哪里使用?
  2. 装饰器将哪些功能添加到未经修饰的基于生成器的协程中?
  3. @asyncio.coroutine@types.coroutine装饰器有何区别?我阅读了此答案以尝试并理解这一点,但是这里提到的唯一区别是types协程如果没有yield语句,则执行起来就像子例程.还有什么吗?
  4. 这些基于生成器的协程与最新的本机async/await协程有何功能和实现上的差异?
  1. How do the yield coroutines relate to the types or asyncio decorated coroutines, and where is the .send() functionality utilized?
  2. What functionality do the decorators add to the undecorated generator-based coroutine?
  3. 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 the types coroutine executes like a subroutine if it has no yield statement. Is there anything more to it?
  4. How do these generator-based coroutines differ in functionality and in implementation from the latest native async/await coroutines?

推荐答案

您可能会笑,我看了

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

所以我认为这只是历史问题,asyncio存在的时间比types长,所以在这里完成了原始处理,然后当类型出现时,真正的包装器就移到了那里,并且asyncio继续只保留了一些内容.多余的包装材料.但归根结底,两者都只是模仿async def

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

这篇关于Python中基于收益的协程与@ asyncio.coroutine和@ types.coroutine装饰器的协程有何不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆