首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >迭代asyncio.coroutine

迭代asyncio.coroutine
EN

Stack Overflow用户
提问于 2014-05-17 09:54:34
回答 3查看 2.9K关注 0票数 8

我最近一直在和异步打交道,当我开始对它的工作方式有直觉的时候,有些事情我还没能做。我不确定这是因为我搞错了建筑,还是我想要做的事情没有道理。

简而言之,我希望能够迭代生成的asyncio.coroutine。例如,我希望能够做这样的事情:

代码语言:javascript
复制
@asyncio.coroutine
def countdown(n):
    while n > 0:
        yield from asyncio.sleep(1)
        n = n - 1
        yield n

@asyncio.coroutine
def do_work():
    for n in countdown(5):
        print(n)

loop.run_until_complete(do_work())

然而,这从异步的中心抛出了一个异常。我尝试过其他一些东西,比如for n in (yield from countdown(5)): ...,但这也提供了类似的不透明运行时异常。

我不明白为什么你不应该这样做,但我已经到了我的能力的极限,了解正在发生的事情。

所以:

  • 如果可以这样做,我怎样才能做到呢?
  • 如果不可能,为甚麽不可能呢?

如果这个问题不清楚请告诉我!

EN

回答 3

Stack Overflow用户

发布于 2014-05-17 12:47:53

在异步协同中,您应该使用yield from,而不是yield。那是故意的。yield from的参数应该是另一个coroutine或asyncio.Future实例。

coroutine本身的调用应该与yield from一起使用,就像yield from countdown(5)一样。

对于您的情况,我建议使用队列:

代码语言:javascript
复制
import asyncio

@asyncio.coroutine
def countdown(n, queue):
    while n > 0:
        yield from asyncio.sleep(1)
        n = n - 1
        yield from queue.put(n)
    yield from queue.put(None)

@asyncio.coroutine
def do_work():
    queue = asyncio.Queue()
    asyncio.async(countdown(5, queue))
    while True:
        v = yield from queue.get()
        if v:
            print(v)
        else:
            break

asyncio.get_event_loop().run_until_complete(do_work())

好的,您可以使用countdown生成的值进行检查,下面的示例是有效的。但我认为这是反模式的:

  1. 太容易弄乱了
  2. 无论如何,您都不能使用例如itertools函数来组合itertools调用。我指的是像sum(countdown(5))itertools.accumulate(countdown(5))这样的东西。

总之,将yieldyield from混合在coroutine中的示例:

代码语言:javascript
复制
import asyncio

@asyncio.coroutine
def countdown(n):
    while n > 0:
        yield from asyncio.sleep(1)
        n = n - 1
        yield n

@asyncio.coroutine
def do_work():
    for n in countdown(5):
        if isinstance(n, asyncio.Future):
            yield from n
        else:
            print(n)

asyncio.get_event_loop().run_until_complete(do_work())
票数 5
EN

Stack Overflow用户

发布于 2015-09-09 13:14:46

在Python3.5中,引入了async for语法。但是,异步迭代器函数语法仍然不存在(即在yield函数中禁止使用async )。这里有一个解决办法:

代码语言:javascript
复制
import asyncio
import inspect

class escape(object):
    def __init__(self, value):
        self.value = value

class _asynciter(object):
    def __init__(self, iterator):
        self.itr = iterator
    async def __aiter__(self):
        return self
    async def __anext__(self):
        try:
            yielded = next(self.itr)
            while inspect.isawaitable(yielded):
                try:
                    result = await yielded
                except Exception as e:
                    yielded = self.itr.throw(e)
                else:
                    yielded = self.itr.send(result)
            else:
                if isinstance(yielded, escape):
                    return yielded.value
                else:
                    return yielded
        except StopIteration:
            raise StopAsyncIteration

def asynciter(f):
    return lambda *arg, **kwarg: _asynciter(f(*arg, **kwarg))

然后,您的代码可以编写为:

代码语言:javascript
复制
@asynciter
def countdown(n):
    while n > 0:
        yield from asyncio.sleep(1)
        #or:
        #yield asyncio.sleep(1)
        n = n - 1
        yield n

async def do_work():
    async for n in countdown(5):
        print(n)

asyncio.get_event_loop().run_until_complete(do_work())

若要了解新语法以及此代码如何工作,请参阅佩普492

票数 4
EN

Stack Overflow用户

发布于 2015-09-02 14:28:53

更好地支持这一点。更新:似乎python3.5

由于遇到了同样的问题(并受到aio-s3代码的启发),我觉得应该有一个更优雅的解决方案。

代码语言:javascript
复制
import asyncio

def countdown(number):
    @asyncio.coroutine
    def sleep(returnvalue):
        yield from asyncio.sleep(1)
        return returnvalue
    for n in range(number, 0, -1):
        yield sleep(n)

@asyncio.coroutine
def print_countdown():
    for future in countdown(5):
        n = yield from future
        print ("Counting down: %d" % n)

asyncio.get_event_loop().run_until_complete(print_countdown())

基本原理:countdown方法产生未来,每个方法将在1秒睡眠后解决所提供的数目。

print_countdown函数接受第一个未来,yield from-ing it (这将暂停直到它被解析)并获得预期的结果:n

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23709916

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档