使用协程时无法让raise Return生效
我最近在尝试使用Python 2.7和Tornado 3.2,想要让一个简单的协程示例运行起来,但一直没成功:
import tornado.web
from tornado.gen import coroutine
from tornado.httpclient import AsyncHTTPClient
from tornado.gen import Return
class MainHandler(tornado.web.RequestHandler):
# Tried with and without @asynchronous
@tornado.web.asynchronous
def get(self):
data = MainService().get_google_data()
self.write(data)
class MainService:
@coroutine
def get_google_data(self):
response = yield AsyncHTTPClient().fetch("http://www.google.com")
raise Return(value = 'hello')
我本以为当我用cURL访问这个网址时,会输出“hello”。结果却是:
...
File "/vagrant/venv/lib/python2.7/site-packages/tornado/web.py", line 656, in write
raise TypeError("write() only accepts bytes, unicode, and dict objects")
TypeError: write() only accepts bytes, unicode, and dict objects
显然,返回了一个Future对象,但当我在这个Future上调用result()
时,又抛出了一个异常:DummyFuture不支持阻塞以获取结果
Tornado的文档说,要从协程返回一个值,需要抛出一个Return异常。看源代码,确实是这样期待的。然而,当我运行它时,似乎并没有效果。
希望能得到一些见解!
1 个回答
4
你需要在调用 get_google_data()
的时候加上 yield
:
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
data = yield MainService().get_google_data()
self.write(data)
Tornado 的协程总是会返回一个 Future
对象。你需要通过在这个 Future
上调用 yield
来等待它的结果。如果不加 yield
,你会立刻得到这个 Future
,而不是等到协程完成后再得到结果。此外,你还应该在 get
方法上使用 @coroutine
装饰器,除了 get_google_data
之外。如果你想使用回调函数而不是协程,通常会用到 @asynchronous
装饰器。