Heim > Artikel > Backend-Entwicklung > Das Tornado-Framework von Python implementiert einen asynchronen, nicht blockierenden Zugriff auf die Datenbank
Tornado ist ein nicht blockierender HTTP-Server. Um ihn zu verwenden, verwenden wir das Tornado-Framework, die Mongodb-Datenbank und den asynchronen Treiber von Mongodb, um einfach die nicht blockierende Funktion von Tornado zu implementieren 🎜>
Download und Installation werden von anderen Umgebungen unterstützt
1. Mongodb installieren
$ sudo apt-get install update $ sudo apt-get install mongodb
2. Motor einbauen
$ pip install motor
Nicht blockierend
# conf.py import os import motor from handlers import index, auth BASE_DIR = os.path.join(__file__) handlers = [ (r'^/$', index.IndexHandler), (r'^/auth/register$', auth.RegisterHandler), (r'^/auth/login$', auth.LoginHandler), ] settings = dict( debug = True, template_path = os.path.join(BASE_DIR, 'templates'), static_path = os.path.join(BASE_DIR, 'static'), ) client = motor.MotorClient("127.0.0.1") db = client.meetStellen Sie zunächst eine Verbindung zur Datenbank in der Konfigurationsdatei her. db_name in client.db_name ist der Name der Datenbank
# handlers/__init__.py class BaseHandler(tornado.web.RequestHandler, TemplateRendering): def initialite(self): ... @property def db(self): return self.application.dbFügen Sie db() hinzu und verwenden Sie die Eigenschaftsdekoration, um wie eine Eigenschaft auf die Datenbank zuzugreifen
# auth.py import os import time import tornado.web from tornado import gen from . import BaseHandler class RegisterHandler(BaseHandler): def get(self): self.render_html('register.html') @tornado.web.asynchronous @gen.coroutine def post(self): username = self.get_argument('username', None) email = self.get_argument('email', None) password = self.get_argument('password', None) data = { 'username': username, 'email': email, 'password': password, 'timestamp': time.time() * 1000, } if username and email: yield self.db.user.insert(data) self.redirect('/') class LoginHandler(BaseHandler): @tornado.web.asynchronous @gen.coroutine def get(self): username = self.get_argument('useranme') user = yield self.db.user.find_one({'username': username}) self.render_html('login.html', user=user)@gen.coroutine-Dekoration macht die Funktion Nicht blockierend und gibt einen generierten Controller zurück, anstatt eine Callback-Funktion zu verwenden. Der Motor implementiert auch asynchron über yield (andernfalls müsste er eine Callback-Funktion zurückgeben). Der Schlüssel liegt darin Die Zeit ist zu kurz.
Ändern wir den Code
# 之前 yield self.db.user.insert(data) # 之后 yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 10)Die Anwendung wird hier durch tornado.ioloop.IOLoop.instance() blockiert. add_timeout. Dies ist eine nicht blockierende Implementierung von time.sleep, da es sich um eine Single-Thread-Anwendung handelt, die die gesamte Anwendung blockiert, sodass andere Handler nicht darauf zugreifen können Nachdem ich mich auf der Registrierungsseite registriert hatte, habe ich während des Sperrzeitraums auf /auth/login geklickt und direkt auf die Anmeldeseite zugegriffen, um den Nicht-Blockierungsvorgang abzuschließen
Umleitungsprobleme unter asynchronen Bedingungen
1 >
Ich möchte eine registrierte Benutzerfunktion implementieren, aber während der Registrierung tritt ein Ausnahmeumleitungsfehler auf:
Ich wollte zur Registrierungsseite springen, wenn der Benutzer den Bestätigungscode falsch eingibt, aber das Problem besteht darin, dass der Code weiterhin ausgeführt wird, obwohl self.finish nach self hinzugefügt wird .redirect beendet den Code, da self.finish bereits in der self.redirect-Funktion vorhanden ist. Es gibt zwei Codes, die eine abnormale Beendigung melden.
Aufgrund des oben genannten Ursachencodes wird es nicht beendet, wenn der Bestätigungscode falsch ist , der Benutzer wird sich trotzdem registrierenclass Register(BaseHandler): def get(self): self.render_html('register.html') @tornado.web.aynchronous @gen.coroutine def post(self): username = self.get_argument('username') email = self.get_argument('email') password = self.get_argument('password') captcha = self.get_argument('captcha') _verify_username = yield self.db.user.find_one({'username': username}) if _verify_username: self.flash(u'用户名已存在', 'error') self.redirect('/auth/register') _verify_email = yield self.db.user.find_one({'email': email}) if _verify_email: self.flash(u'邮箱已注册', 'error') self.redirect('/auth/register') if captcha and captcha == self.get_secure_cookie('captcha').replace(' ',''): self.flash(u'验证码输入正确', 'info') else: self.flash(u'验证码输入错误', 'error') self.redirect('/auth/register') password = haslib.md5(password + self.settings['site']).hexdigest() profile = {'headimg': '', 'site': '', 'job': '', 'signature':'', 'github': '', 'description': ''} user_profile = yield self.db.profile.insert(profile) user = {'username': username, 'email': email, 'password': password, 'timestamp': time.time(), 'profile_id': str(user_profile)} yield self.db.user.insert(user) self.set_secure_cookie('user', username) self.redirect('/')
(1) Die Antwort des begeisterten Benutzers rsj217 in segmentdefault
return self.redirect('/auth/register')self.finish schließt die Anfrage, weil @ tornado.web.aynchronous Tornado das mitteilt es wird auf die Anfrage warten (langer Link). self.redirect entspricht dem Festlegen des Standortattributs der Antwortheader (2) Die Antwort des begeisterten Benutzers Evian in segmentdefault
Selbst. Finish springt natürlich nicht aus der Funktion heraus. Was ist sonst, wenn Sie etwas tun möchten, nachdem die Anfrage abgeschlossen ist?
3.Zusammenfassung
self.redirect('/auth/register') return
self.redirect legt den Speicherort in request.headers für Jump fest
self.finish schließt die Anfrage, schließt sie aber nicht aus der Funktion springen