Heim  >  Artikel  >  Backend-Entwicklung  >  Das Tornado-Framework von Python implementiert einen asynchronen, nicht blockierenden Zugriff auf die Datenbank

Das Tornado-Framework von Python implementiert einen asynchronen, nicht blockierenden Zugriff auf die Datenbank

高洛峰
高洛峰Original
2017-03-01 13:45:072455Durchsuche

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.meet
Stellen 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.db
Fü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

Bei der Verwendung von Tornado stoße ich häufig auf Probleme. (Vielen Dank, dass Sie mir bei der Beantwortung meiner Zweifel geholfen haben.)

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 registrieren

class 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

Weil self .finish war fälschlicherweise Das obige Problem tritt auf, wenn eine Jump-Out-Funktion verwendet wird
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

Weitere Artikel zum Python-Framework Tornado, das asynchronen, nicht blockierenden Zugriff auf die Datenbank implementiert, finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn