Python中基于收益的协程与使用@ asyncio.coroutine和@ types.coroutine装饰器的协程有何不同?

时间:2019-07-15 22:55:38

标签: python asynchronous async-await generator coroutine

我一直试图理解异步编程,尤其是在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协程在功能和实现上有何不同?

1 个答案:

答案 0 :(得分:0)

您可能会笑,我看了一下https://www-01.ibm.com/support/docview.wss?uid=swg27011920,发现它使用了types.coroutine (我添加了任何带有#!>的评论)< / p>

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更长,因此在此完成了原始处理,然后当类型出现时,将真正的包装器移到那里,并且异步继续只是有一些额外的包装材料。但归根结底,两者都只是模仿async def

的行为