我最近一直在和异步打交道,当我开始对它的工作方式有直觉的时候,有些事情我还没能做。我不确定这是因为我搞错了建筑,还是我想要做的事情没有道理。
简而言之,我希望能够迭代生成的asyncio.coroutine。例如,我希望能够做这样的事情:
@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)): ...,但这也提供了类似的不透明运行时异常。
我不明白为什么你不应该这样做,但我已经到了我的能力的极限,了解正在发生的事情。
所以:
如果这个问题不清楚请告诉我!
发布于 2014-05-17 12:47:53
在异步协同中,您应该使用yield from,而不是yield。那是故意的。yield from的参数应该是另一个coroutine或asyncio.Future实例。
coroutine本身的调用应该与yield from一起使用,就像yield from countdown(5)一样。
对于您的情况,我建议使用队列:
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生成的值进行检查,下面的示例是有效的。但我认为这是反模式的:
itertools函数来组合itertools调用。我指的是像sum(countdown(5))或itertools.accumulate(countdown(5))这样的东西。总之,将yield和yield from混合在coroutine中的示例:
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())发布于 2015-09-09 13:14:46
在Python3.5中,引入了async for语法。但是,异步迭代器函数语法仍然不存在(即在yield函数中禁止使用async )。这里有一个解决办法:
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))然后,您的代码可以编写为:
@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。
发布于 2015-09-02 14:28:53
更好地支持这一点。更新:似乎python3.5
由于遇到了同样的问题(并受到aio-s3代码的启发),我觉得应该有一个更优雅的解决方案。
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。
https://stackoverflow.com/questions/23709916
复制相似问题