Tornado coroutine

Estoy tratando de aprender tornado coroutines, pero tengo un error al usar el siguiente código.

Traceback (most recent call last): File "D:\projekty\tornado\env\lib\site-packages\tornado\web.py", line 1334, in _execute result = yield result File "D:\projekty\tornado\env\lib\site-packages\tornado\gen.py", line 628, in run value = future.result() File "D:\projekty\tornado\env\lib\site-packages\tornado\concurrent.py", line 109, in result raise_exc_info(self._exc_info) File "D:\projekty\tornado\env\lib\site-packages\tornado\gen.py", line 631, in run yielded = self.gen.throw(*sys.exc_info()) File "index.py", line 20, in get x = yield 'test' File "D:\projekty\tornado\env\lib\site-packages\tornado\gen.py", line 628, in run value = future.result() File "D:\projekty\tornado\env\lib\site-packages\tornado\concurrent.py", line 111, in result raise self._exception BadYieldError: yielded unknown object 'test' 

Código:

 from tornado.ioloop import IOLoop from tornado.web import RequestHandler, Application, url from tornado import gen class HelloHandler(RequestHandler): @gen.coroutine def get(self): x = yield 'test' self.render('hello.html') def make_app(): return Application( [url(r"/", HelloHandler)], debug = True ) def main(): app = make_app() app.listen(8888) IOLoop.instance().start() main() 

Como señaló Lutz Horn, el decorador de tornado.coroutine requiere que tornado.coroutine solo objetos Future o ciertos contenedores que contengan objetos Future . Por lo tanto, tratar de producir un str generará un error. Creo que la pieza que te falta es que cualquier lugar dentro de una coroutine al que quieras llamar yield something() , something debe ser una coroutine o devolver un Future . Por ejemplo, podrías arreglar tu ejemplo como este:

 from tornado.gen import Return class HelloHandler(RequestHandler): @gen.coroutine def get(self): x = yield self.do_test() self.render('hello.html') @gen.coroutine def do_test(self): raise Return('test') # return 'test' # Python 3.3+ 

O incluso esto (aunque generalmente no deberías hacerlo de esta manera):

 class HelloHandler(RequestHandler): @gen.coroutine def get(self): x = yield self.do_test() self.render('hello.html') def do_test(self): fut = Future() fut.set_result("test") return fut 

Por supuesto, estos son ejemplos artificiales; Ya que no estamos haciendo nada asíncrono en do_test , no hay razón para hacer que sea una coroutine. Normalmente estarías haciendo algún tipo de E / S asíncrona allí. Por ejemplo:

 class HelloHandler(RequestHandler): @gen.coroutine def get(self): x = yield self.do_test() self.render('hello.html') @gen.coroutine def do_test(self): http_client = AsyncHTTPClient() out = yield http_client.fetch("someurl.com") # fetch is a coroutine raise Return(out.body) # return out.body # Python 3.3+ 

De la documentación :

La mayoría de las funciones asíncronas en Tornado devuelven un Future ; produciendo este objeto devuelve su resultado.

También puede yield a list or dict of Futures , que se iniciarán al mismo tiempo y se ejecutarán en paralelo; se devolverá una lista o dictado de los resultados cuando estén terminados:

La cadena "test" no es un Future . Trate de ceder uno.