2016-05-31 24 views
0

Ich bin ziemlich neu in der Programmierung mit Coroutinen und ich versuche, eine Datenbank-Schnittstelle für eine benutzerdefinierte Datenbank für einen Tornado-Webserver mit Python 2.7.10 zu erstellen. Allerdings bekomme ich immer eine BadYieldError. Ich fühle, dass dies ist wahrscheinlich nicht ich verstehe, wie tornado.gen.coroutine mit Pythons yield vollständig zu verwenden. Ich denke, dass etwas daran falsch ist, wie ich eine Zukunft ergebe.Python BadYieldError beim Rendern Future

Dies ist mein Code, der weiterhin fehlschlägt, wobei die testGet-Funktion in Zeile 15 eine Simulation eines fremden Datenbankzugriffs ist.

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

Ausgang:

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 

Ich habe versucht, zu suchen, wie dies auf Tornado's official documentation richtig zu machen und auf this blog, aber ich glaube nicht, ich habe in der Lage gewesen, was vollständig zu erfassen Sie sagen, wie man Koroutinen benutzt.

Antwort

2

Drehen Sie testGet in eine Koroutine wie dies so, dass es eine Zukunft gibt:

@gen.coroutine 
def testGet(query): 
    gen.sleep(2) 
    raise gen.Return(query) 

Oder verwenden Sie nicht yield darauf: d = testGet(key).

Wenn Sie beides tun, funktioniert der Code. Sie sollten yield für Funktionen verwenden, die Future s zurückgeben.

+0

Gut 'testGet' wäre ein Datenbankaufruf, keine Funktion, also kann ich es nicht in eine Coroutine verwandeln. Kann ich irgendwie von einer Funktion, die nachgibt, nachgeben? Und wenn ja, ist das eine schlechte Idee? – goatandsheep

+0

Ich gab zwei Optionen in der Antwort: Konvertiere zu Coroutine oder lasse die 'Ausbeute' von' d = yield testGet (key) 'fallen. Willst du sagen, keine Option Arbeit? – Louis

+0

Es ist mir nicht möglich, 'testGet' in eine Coroutine zu verwandeln, da es sich nicht um eine Funktion handelt, sondern um eine Darstellung eines fremden Anrufs, den ich zu Demonstrationszwecken verwende. Der zweite funktioniert, aber warum? Ist es nicht möglich, eine Zukunft, die eine Zukunft darstellt, auszugeben? Wenn ja, was habe ich falsch gemacht, dass Ihre Lösung besser ist? – goatandsheep