使用协程时无法让raise Return生效

0 投票
1 回答
1380 浏览
提问于 2025-04-28 05:19

我最近在尝试使用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 装饰器。

撰写回答