可以在没有等待或屈服的情况下实现Python协程吗?

时间:2019-03-07 08:49:22

标签: python iterator generator python-asyncio coroutine

我正在学习Python await / async语法,想知道如何在没有异步,await或yield的情况下实现协程。例如,我使用异步def语法使这个简单的三秒钟计时器成为一个计时器:

import asyncio

async def coroutine():
    count = 0
    while count < 3:
        count += 1
        print(count)
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine())
loop.close()

结果:

1
2
3

我注意到我们可以通过实现__await__https://docs.python.org/3.6/reference/datamodel.html#awaitable-objects)来实现Coroutine对象。这样我就可以成功删除await

import asyncio

class Generator():
    def __await__(self):
        count = 0
        while count < 3:
            count += 1
            print(count)
            yield from asyncio.sleep(1)

loop = asyncio.get_event_loop()
loop.run_until_complete(Generator())
loop.close()

最后,我想实现没有这样的收益的迭代器:

import asyncio

class Iterator():

    def __init__(self):
        self.count = 0

    def __iter__(self): return self

    def __await__(self): return self

    def __next__(self):
        if self.count < 3:
            self.count += 1
            print(self.count)
            return next(asyncio.sleep(1))
        else:
            raise StopIteration()

loop = asyncio.get_event_loop()
result = loop.run_until_complete(Iterator())
loop.close()

但是没有用。它显示“ 1”后停止。

我知道这没有任何实际价值,但是我想知道它可以正确理解asyncio。我可以在没有等待或屈服的情况下实现协程吗?如果可以,该怎么办?我通过Python 3.6.7进行了测试。

1 个答案:

答案 0 :(得分:1)

虽然协程使用 生成器实现,但协程不是生成器:

import asyncio
from typing import Generator


def gen():
    yield 1


async def coro():
    pass


print(isinstance(gen(), Generator))   # True
print(isinstance(coro(), Generator))  # False

这是有意的,因为生成器仅是实现协程的一个细节。迭代器也是如此:协程不是迭代器。

loop.run_until_complete希望收到诸如asyncio协程或未来之类的东西。您正在尝试传递迭代器-具有不同行为的另一个对象。


长话短说,如果您想实现与asyncio兼容的协程:

  • 使用async def定义函数
  • 或实施__await__魔术方法

并阅读asyncio doc作为示例。

如果您想了解协程如何在非常低的层次上工作的一般思路,可以遵循excellent video,David Beazley从头开始实现协程和事件循环。

相关问题