Nach der Veröffentlichung von tornado3 wurde das Konzept der Coroutine in der asynchronen Programmierung gestärkt, es ersetzte die ursprüngliche gen.engine und wurde zur aktuellen gen.coroutine. Dieser Dekorator wurde ursprünglich entwickelt, um die asynchrone Programmierung in Tornado zu vereinfachen. Vermeiden Sie das Schreiben von Rückruffunktionen, um die Entwicklung besser mit dem normalen logischen Denken in Einklang zu bringen. Ein einfaches Beispiel lautet wie folgt:
class MaindHandler(web.RequestHandler):
@asynchronous
@gen.coroutine
def post(self):
client = AsyncHTTPClient()
resp = yield client.fetch(https://api.github.com/users")
if resp.code == 200:
resp = escape.json_decode(resp.body)
self.write(json.dumps(resp, indent=4, Separatoren=( ' ,', ':')))
else:
resp = {"message": "error when fetch etwas"}
self.write(json. dumps (bzw. indent=4, Separatoren={',', ':')))
self.finish()
Nach der yield-Anweisung registriert ioloop das Ereignis und wartet Bis die Ausführung nach der Rückkehr von resp. fortgesetzt wird, wird hier json.dumps anstelle von escape.json_encode verwendet, da beim Erstellen einer REST-API häufig über den Browser auf JSON zugegriffen wird .dumps zum Formatieren der Daten ist für Benutzer dieses Stils benutzerfreundlicher, wenn sie eine Pull-Anfrage senden Der Autor antwortete, dass Escape nicht die Absicht habe, alle JSON-Funktionen selbst bereitzustellen
Gen >
sagt = (yield)
print sagt
if __name__ == "__main__": client = test_yield()
client.next()
client.send("hello world")
Die Ausgabeergebnisse lauten wie folgt:
test yeild Hallo Welt
Eine bereits laufende Funktion wird angehalten, bis der Client, der sie aufruft, die Sendemethode verwendet und die ursprüngliche Funktion weiterhin ausgeführt wird. Die gen.coroutine-Methode besteht hier darin, die erforderlichen Vorgänge asynchron auszuführen und dann auf die Rückgabe des Ergebnisses zu warten, bevor sie an die ursprüngliche Funktion gesendet wird, die weiterhin ausgeführt wird. Auf diese Weise wird der synchron geschriebene Code erreicht Auswirkung der asynchronen Ausführung.
client = AsyncHTTPClient()
resp = yield client.fetch("https://api.github.com/users")
if resp == 200:
body = escape.json_decode(resy .body)
else:
body = {"message": "client fetch error"}
logger.error("client fetch error %d, %s" % (resp .code, resp.message))
self.write(escape.json_encode(body))
self.finish()
kann danach so werden Wechsel zu einer Funktion ;
@gen.coroutimedef post(self):
resp = yield GetUser()
self.write(resp)
@gen.coroutinedef GetUser():
client = AsyncHTTPClient( )
resp = yield client.fetch("https://api.github.com/users")
if resp.code == 200:
resp = escape.json_decode( resp.body)
else:
resp = {"message": "fetch client error"}
logger.error("client fetch error % d, %s " % (resp.code, resp.message))
raise gen.Return(resp)
Wenn Asynchron in einer Funktion gekapselt ist, stellt das Gen-Modul anstelle des Schlüsselworts „return“ für die Rückgabe wie bei einem normalen Programm eine Methode „gen.Return“ bereit. Dies wird durch die Raise-Methode erreicht. Dies hängt auch damit zusammen, dass die Umsetzung über einen Generator erfolgt.
Verwenden Sie Coroutine, um geplante Aufgaben auszuführen
In Tornado gibt es eine solche Methode:
tornado.ioloop.IOLoop.instance().add_timeout()
Diese Methode ist eine nicht blockierende Version von time.sleep, die zwei Parameter akzeptiert: eine Zeitlänge und eine Funktion. Gibt die Zeitspanne an, nach der die Funktion aufgerufen wird. Hier basiert es auf ioloop und ist daher nicht blockierend. Diese Methode wird häufig bei der Programmierung langer Clientverbindungen und Rückruffunktionen verwendet. Es ist jedoch nutzlos, es zum Ausführen einiger geplanter Aufgaben zu verwenden. Normalerweise ist es nicht erforderlich, es beim Ausführen geplanter Aufgaben zu verwenden. Aber als ich Heroku benutzte, stellte ich fest, dass ich, wenn ich keine Kreditkarte registrierte, nur das Hosten einer einfachen Webanwendung nutzen konnte. Geplante Aufgaben zur Ausführung können nicht hinzugefügt werden. Also habe ich mir eine solche Methode ausgedacht. Hier verwende ich es hauptsächlich, um in regelmäßigen Abständen Daten über die Github-API-Schnittstelle abzurufen. Die Verwendungsmethode ist wie folgt:
Decorator
def sync_loop_call(delta=60 * 1000):
"""
Warte auf func down und verarbeite dann add_timeout
"""
def wrap_loop(func):
@ wraps( Func)
@geen.coroutine
DEF WRAP_FUNC (*ARGS, ** KWARGS):
Options.logger.info ("Funktion %R Start AT % D" %
. (func.__name__, e))
Optionen . Logger.info ("Funktion %R Ende AT %D" %
(Func .__ Name__, int (Time.time ())))
tornado.ioloop.instance ( ).add_timeout(
datetime.timedelta(milliseconds=delta),
wrap_func)
return wrap_func
return wrap_loop
Task Function
@sync_loop_call(delta=10 * 1000) def worker(): """ Etwas tun
" ""
Aufgabe hinzufügen
if __name__ == "__main__": worker () app. listen(options.port) tornado.ioloop.IOLoop.instance().start()
Danach wird beim Start der Webanwendung die geplante Aufgabe entsprechend ausgeführt, und weil Da sie ereignisbasiert ist und asynchron ausgeführt wird, hat sie keinen Einfluss auf den normalen Betrieb des Webdienstes. Natürlich kann die Aufgabe nicht blockierend oder rechenintensiv sein. Ich erfasse hier hauptsächlich Daten und verwende die asynchrone Erfassungsmethode, die mit Tornado geliefert wird.
Vollständige Beispiele finden Sie auf meinem Github. Dieses Projekt basiert auf Heroku. Wird verwendet, um Github-Benutzeraktivitätsrankings und regionale Benutzerverteilung anzuzeigen. Sie können Github-Data zur Ansicht besuchen. Da Heroku in China blockiert ist, müssen Sie über die Mauer klettern, um darauf zuzugreifen.
Zusammenfassung
Tornado ist ein nicht blockierender Webserver und ein Webframework, aber wenn Sie es verwenden, können Sie dies tun Nur asynchrone Bibliotheken können ihre asynchronen Funktionen wirklich nutzen. Da die App selbst jedoch nicht sehr anspruchsvoll ist, gibt es natürlich kein Problem, wenn die Blockierung nicht besonders schwerwiegend ist. Wenn Sie außerdem das Coroutine-Modul für die asynchrone Programmierung verwenden und eine Funktion in eine Funktion einkapselt, wird dieser Fehler auch dann nicht ausgelöst, wenn während der Ausführung der Funktion ein Fehler auftritt, wenn er nicht abgefangen wird, was das Debuggen sehr erschwert.