【发布时间】:2016-05-12 21:15:01
【问题描述】:
在下面的代码示例中,我有一个函数do_async_thing,它似乎返回一个Future,尽管我不确定为什么?
import tornado.ioloop
import tornado.web
import tornado.httpclient
@tornado.gen.coroutine
def do_async_thing():
http = tornado.httpclient.AsyncHTTPClient()
response = yield http.fetch("http://www.google.com/")
return response.body
class MainHandler(tornado.web.RequestHandler):
def get(self):
x = do_async_thing()
print(x) # <tornado.concurrent.Future object at 0x10753a6a0>
self.set_header("Content-Type", "application/json")
self.write('{"foo":"bar"}')
self.finish()
if __name__ == "__main__":
app = tornado.web.Application([
(r"/foo/?", MainHandler),
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
你会看到我yield 调用了fetch,这样做我应该强制该值实现(随后能够访问body 字段的响应)。
更有趣的是我什至可以访问 Future 上的 body 字段并且不会出错(据我所知,Future 没有这样的字段/属性/方法)
那么有谁知道我该怎么做:
- 解决未来,让我得到实际价值
- 修改此示例,使函数
do_async_thing进行多个异步 url 获取
现在值得注意的是,因为我仍然得到 Future 回来,所以我想我会尝试添加一个 yield 来为对 do_async_thing() 的调用添加前缀(例如 x = yield do_async_thing()),但这给了我以下错误:
tornado.gen.BadYieldError: yielded unknown object <generator object get at 0x1023bc308>
第二点我也考虑过这样做:
def do_another_async_thing():
http = tornado.httpclient.AsyncHTTPClient()
a = http.fetch("http://www.google.com/")
b = http.fetch("http://www.github.com/")
return a, b
class MainHandler(tornado.web.RequestHandler):
def get(self):
y = do_another_async_thing()
print(y)
但这又会返回:
<tornado.concurrent.Future object at 0x102b966d8>
至少我会期望一个 Futures 元组在哪里?在这一点上,我无法解决这些期货,而不会出现以下错误:
tornado.gen.BadYieldError: yielded unknown object <generator object get at 0x1091ac360>
更新
以下是一个有效的示例(根据 A. Jesse Jiryu Davis 的回答)
但我还添加了另一个示例,其中我有一个新函数 do_another_async_thing,它使 两个 异步 HTTP 请求(但评估它们的值会更复杂一点,正如您将看到的那样):
def do_another_async_thing():
http = tornado.httpclient.AsyncHTTPClient()
a = http.fetch("http://www.google.com/")
b = http.fetch("http://www.github.com/")
return a, b
@tornado.gen.coroutine
def do_async_thing():
http = tornado.httpclient.AsyncHTTPClient()
response = yield http.fetch("http://www.google.com/")
return response.body
class MainHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
def get(self):
x = yield do_async_thing()
print(x) # displays HTML response
fa, fb = do_another_async_thing()
fa = yield fa
fb = yield fb
print(fa.body, fb.body) # displays HTML response for each
值得澄清:您可能认为do_another_async_thing 的两个yield 语句会导致阻塞。但这里是正在发生的步骤的细分:
-
do_another_async_thing立即返回一个包含两个 Future 的元组 - 我们
yield第一个导致程序阻塞直到值实现的元组 - 值实现了,所以我们转到下一行
- 我们再次
yield,导致程序阻塞,直到值实现 - 但由于两个期货同时创建并同时运行,第二个
yield几乎立即返回
【问题讨论】:
标签: python concurrency tornado