Python 产生 Future 时出现 BadYieldError
Python BadYieldError when yielding Future
我对使用协程进行编程还很陌生,我正在尝试使用 Python 2.7.10 为 Tornado Web 服务器的自定义数据库构建数据库接口。但是,我一直收到 BadYieldError
。我觉得这可能是我没有理解如何充分利用 tornado.gen.coroutine
和 Python 的 yield
。我认为我产生 Future 的方式可能有问题。
这是我一直失败的代码,其中第15行的testGet
函数是模拟外部数据库访问。
from tornado import gen
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
response = "Hello, world"
response = yield db_interface("default", "user_query")
self.write(str(response))
# meant to demonstrate
def testGet(query):
gen.sleep(2)
response = query
return response
@gen.coroutine
def db_interface(db, key):
print str(db)
d = yield testGet(key)
raise gen.Return(d)
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8889)
tornado.ioloop.IOLoop.current().start()
输出:
default
ERROR:tornado.application:Uncaught exception GET / (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:8889', method='GET', uri='/', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Accept-Language': 'en-CA,en;q=0.8,fr;q=0.6', 'Accept-Encoding': 'gzip, deflate, sdch', 'Host': '127.0.0.1:8889', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36', 'Dnt': '1', 'Connection': 'keep-alive', 'Cookie': 'ui-auth-127.0.0.1%3A8091=4f1301ef98f1b6fbd80ad059cd5aa2dc', 'Cache-Control': 'max-age=0', 'Upgrade-Insecure-Requests': '1'})
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/tornado/web.py", line 1415, in _execute
result = yield result
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
value = future.result()
File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 876, in run
yielded = self.gen.throw(*exc_info)
File "test.py", line 12, in get
response = yield db_interface("default", "user_query")
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
value = future.result()
File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 876, in run
yielded = self.gen.throw(*exc_info)
File "test.py", line 26, in db_interface
d = yield testGet(key)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
value = future.result()
File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 956, in handle_yield
self.future = convert_yielded(yielded)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 1026, in convert_yielded
raise BadYieldError("yielded unknown object %r" % (yielded,))
BadYieldError: yielded unknown object 'user_query'
ERROR:tornado.access:500 GET / (127.0.0.1) 2011.67ms
我一直在尝试寻找如何在 Tornado's official documentation and on this blog 上正确执行此操作,但我认为我无法完全理解他们所说的有关如何使用协程的内容。
要么将 testGet
变成像这样的协程,以便它 return 成为未来:
@gen.coroutine
def testGet(query):
gen.sleep(2)
raise gen.Return(query)
或者不使用yield
:d = testGet(key)
。
如果您这样做,则代码有效。您应该在 return Future
的函数上使用 yield
。
我对使用协程进行编程还很陌生,我正在尝试使用 Python 2.7.10 为 Tornado Web 服务器的自定义数据库构建数据库接口。但是,我一直收到 BadYieldError
。我觉得这可能是我没有理解如何充分利用 tornado.gen.coroutine
和 Python 的 yield
。我认为我产生 Future 的方式可能有问题。
这是我一直失败的代码,其中第15行的testGet
函数是模拟外部数据库访问。
from tornado import gen
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
response = "Hello, world"
response = yield db_interface("default", "user_query")
self.write(str(response))
# meant to demonstrate
def testGet(query):
gen.sleep(2)
response = query
return response
@gen.coroutine
def db_interface(db, key):
print str(db)
d = yield testGet(key)
raise gen.Return(d)
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8889)
tornado.ioloop.IOLoop.current().start()
输出:
default
ERROR:tornado.application:Uncaught exception GET / (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:8889', method='GET', uri='/', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Accept-Language': 'en-CA,en;q=0.8,fr;q=0.6', 'Accept-Encoding': 'gzip, deflate, sdch', 'Host': '127.0.0.1:8889', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36', 'Dnt': '1', 'Connection': 'keep-alive', 'Cookie': 'ui-auth-127.0.0.1%3A8091=4f1301ef98f1b6fbd80ad059cd5aa2dc', 'Cache-Control': 'max-age=0', 'Upgrade-Insecure-Requests': '1'})
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/tornado/web.py", line 1415, in _execute
result = yield result
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
value = future.result()
File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 876, in run
yielded = self.gen.throw(*exc_info)
File "test.py", line 12, in get
response = yield db_interface("default", "user_query")
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
value = future.result()
File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 876, in run
yielded = self.gen.throw(*exc_info)
File "test.py", line 26, in db_interface
d = yield testGet(key)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
value = future.result()
File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
raise_exc_info(self._exc_info)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 956, in handle_yield
self.future = convert_yielded(yielded)
File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 1026, in convert_yielded
raise BadYieldError("yielded unknown object %r" % (yielded,))
BadYieldError: yielded unknown object 'user_query'
ERROR:tornado.access:500 GET / (127.0.0.1) 2011.67ms
我一直在尝试寻找如何在 Tornado's official documentation and on this blog 上正确执行此操作,但我认为我无法完全理解他们所说的有关如何使用协程的内容。
要么将 testGet
变成像这样的协程,以便它 return 成为未来:
@gen.coroutine
def testGet(query):
gen.sleep(2)
raise gen.Return(query)
或者不使用yield
:d = testGet(key)
。
如果您这样做,则代码有效。您应该在 return Future
的函数上使用 yield
。