【发布时间】:2014-01-10 19:40:38
【问题描述】:
考虑以下程序(在 CPython 3.4.0b1 上运行):
import math
import asyncio
from asyncio import coroutine
@coroutine
def fast_sqrt(x):
future = asyncio.Future()
if x >= 0:
future.set_result(math.sqrt(x))
else:
future.set_exception(Exception("negative number"))
return future
def slow_sqrt(x):
yield from asyncio.sleep(1)
future = asyncio.Future()
if x >= 0:
future.set_result(math.sqrt(x))
else:
future.set_exception(Exception("negative number"))
return future
@coroutine
def run_test():
for x in [2, -2]:
for f in [fast_sqrt, slow_sqrt]:
try:
future = yield from f(x)
print("\n{} {}".format(future, type(future)))
res = future.result()
print("{} result: {}".format(f, res))
except Exception as e:
print("{} exception: {}".format(f, e))
loop = asyncio.get_event_loop()
loop.run_until_complete(run_test())
我有 2 个(相关的)问题:
即使在
fast_sqrt上使用装饰器,Python 似乎也完全优化了在fast_sqrt中创建的 Future,并返回了一个普通的float。然后在yield fromrun_test()中爆炸为什么我需要评估
future.result()中的run_test来检索引发异常的值? docs 说yield from <future>“暂停协程直到未来完成,然后返回未来的结果,或者引发异常”。为什么我需要手动检索未来的结果?
这是我得到的:
oberstet@COREI7 ~/scm/tavendo/infrequent/scratchbox/python/asyncio (master)
$ python3 -V
Python 3.4.0b1
oberstet@COREI7 ~/scm/tavendo/infrequent/scratchbox/python/asyncio (master)
$ python3 test3.py
1.4142135623730951 <class 'float'>
<function fast_sqrt at 0x00B889C0> exception: 'float' object has no attribute 'result'
Future<result=1.4142135623730951> <class 'asyncio.futures.Future'>
<function slow_sqrt at 0x02AC8810> result: 1.4142135623730951
<function fast_sqrt at 0x00B889C0> exception: negative number
Future<exception=Exception('negative number',)> <class 'asyncio.futures.Future'>
<function slow_sqrt at 0x02AC8810> exception: negative number
oberstet@COREI7 ~/scm/tavendo/infrequent/scratchbox/python/asyncio (master)
好的,我找到了“问题”。 slow_sqrt 中的 yield from asyncio.sleep 将自动使其成为协程。等待需要以不同的方式进行:
def slow_sqrt(x):
loop = asyncio.get_event_loop()
future = asyncio.Future()
def doit():
if x >= 0:
future.set_result(math.sqrt(x))
else:
future.set_exception(Exception("negative number"))
loop.call_later(1, doit)
return future
所有 4 个变体都是 here。
【问题讨论】:
-
这在 Python 3.3 中有效还是只是测试版中的一个错误?
-
我没有安装 3.3.. 会检查。
-
关于第一个问题,哪里炸了?在
future = yield from f(x)或res = future.result()? -
@delnan on
yield from f(x)..float is not iterable。事实上,没有装饰器,fast_sqrt将返回一个float(不再是future)。 -
@oberstet 我发现这非常很难相信(它使我对
asyncio的理解无效,否则就解释了你的描述)。您能否仔细检查此处发布的代码是否是导致该问题的代码?换句话说,请复制并粘贴此问题的代码,删除@coroutine,运行它并显示回溯。我自己会这样做,但我既没有可用的 3.4 beta 也没有包管理器来测试 asyncio-for-3.3。
标签: python future yield coroutine python-asyncio