2014-11-20 22 views
11

Próbuję nauczyć się coroutines tornado, ale mam błąd przy użyciu poniższego kodu.Tornado coroutine

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' 

Kod:

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() 
+0

Co próbujesz zrobić w linii 'x = wydajność '? –

+0

który jest tylko przykładem, próbowałem również uzyskać wynik funkcji - wynik jest taki sam, ta linia służy tylko do testowania coroutines – klis87

Odpowiedz

26

Jak zauważył Lutz Horn, dekorator tornado.coroutine wymaga dostarczenia tylko obiektów o wartości Future lub niektórych pojemników zawierających obiekty Future. Tak więc próba uzyskania str spowoduje błąd. Wydaje mi się, że brakuje Ci jakiegoś elementu wewnątrz coroutine, w którym chcesz zadzwonić pod numer yield something(), something, ale musi to być również coroutine lub zwróć Future. Na przykład, można naprawić przykład tak:

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+ 

lub nawet ten (choć na ogół nie należy robić to w ten sposób):

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 

Oczywiście, są wymyślonych przykłady; ponieważ w rzeczywistości nie robimy niczego asynchronicznego w do_test, nie ma powodu, aby był to coroutine. Normalnie robiłbyś tam asynchroniczne wejścia/wyjścia. Na przykład:

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+ 
+0

Dzięki za wspaniałą odpowiedź, dodałem time.sleep na początku funkcji do_test, i wszystko działa jak w kodzie synchronicznym, otrzymuję self.render wykonany po skończeniu się snu (x), myślałem, że może ta funkcja jest wykonywana w tle, jednak nie jest tak ... Jaka jest korzyść z używania coroutines? Może inny użytkownik mógłby otworzyć połączenie w tym samym czasie przed zakończeniem snu poprzedniego użytkownika? – klis87

+2

@ user3575996 Użycie 'yield function()' spowoduje, że wykonanie coroutine zaczeka na zakończenie funkcji 'function()'. Jednak * nie * zablokuje pętlę We/Wy tornada, więc jeśli pojawią się inne żądania od klientów, te mogą być obsługiwane w międzyczasie. Jednak nie można użyć 'time.sleep()', aby przetestować to, ponieważ jest to funkcja blokująca. Musisz użyć nieblokującej wersji snu. Zobacz [tę odpowiedź] (http://stackoverflow.com/a/23876402/2073595) na przykład. – dano

+0

Dzięki, teraz w końcu wszystko rozumiem :) – klis87

3

From the documentation:

Większość asynchroniczne funkcje w Tornado zwróci Future; poddanie tego obiektu zwraca jego wynik.

Można również yield a list or dict of Futures, która zostanie uruchomiona w tym samym czasie i uruchomiona równolegle; zostanie zwrócona lista lub dict wyników, gdy są one wykończone:

Ciąg "test" nie jest Future. Spróbuj go wydać.

+2

Powiedzmy, że chcę uzyskać wynik zapytania bazy danych, powiedzmy, funkcja get_all_users() robi to dla ja, czy mógłbyś podać mi przykład, jak przykłady tornado używają wbudowanych klas takich jak AsyncHTTPClient(), jak zaimplementować swój własny – klis87