Maison  >  Article  >  développement back-end  >  Le framework Tornado de Python implémente un accès asynchrone non bloquant à la base de données

Le framework Tornado de Python implémente un accès asynchrone non bloquant à la base de données

高洛峰
高洛峰original
2017-03-01 13:45:072454parcourir

tornado est un serveur http non bloquant. Pour l'utiliser, nous utiliserons le framework tornado, la base de données mongodb et le moteur (le pilote asynchrone de mongodb) pour implémenter simplement la fonction non bloquante de tornado

<.>

Téléchargement et installation pris en charge par d'autres environnements

1 Installer mongodb

$ sudo apt-get install update
$ sudo apt-get install mongodb

<.>

2. Installer le moteur

$ pip install motor

Non bloquant

# conf.py

import os
import motor
from handlers import index, auth

BASE_DIR = os.path.join(__file__)

handlers = [
  (r&#39;^/$&#39;, index.IndexHandler),
  (r&#39;^/auth/register$&#39;, auth.RegisterHandler),
  (r&#39;^/auth/login$&#39;, auth.LoginHandler),
]

settings = dict(
  debug = True,
  template_path = os.path.join(BASE_DIR, &#39;templates&#39;),
  static_path = os.path.join(BASE_DIR, &#39;static&#39;),
)

client = motor.MotorClient("127.0.0.1")
db = client.meet

Connectez-vous d'abord à la base de données dans le fichier de configuration, db_name dans client.db_name est le nom de la base de données

 # handlers/__init__.py
class BaseHandler(tornado.web.RequestHandler, TemplateRendering):
  def initialite(self):
    ...

  @property
  def db(self):
    return self.application.db

Ajoutez db() et utilisez la décoration de propriété pour accéder à la base de données comme une propriété

# 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(&#39;register.html&#39;)

  @tornado.web.asynchronous
  @gen.coroutine
  def post(self):
    username = self.get_argument(&#39;username&#39;, None)
    email = self.get_argument(&#39;email&#39;, None)
    password = self.get_argument(&#39;password&#39;, None)

    data = {
      &#39;username&#39;: username,
      &#39;email&#39;: email,
      &#39;password&#39;: password,
      &#39;timestamp&#39;: time.time() * 1000,
    }

    if username and email:
      yield self.db.user.insert(data)
    self.redirect(&#39;/&#39;)

class LoginHandler(BaseHandler):
  
  @tornado.web.asynchronous
  @gen.coroutine
  def get(self):
    username = self.get_argument(&#39;useranme&#39;)
    user = yield self.db.user.find_one({&#39;username&#39;: username})
    self.render_html(&#39;login.html&#39;, user=user)

@gen.coroutine decoration fait la fonction. non bloquant et renvoie un contrôleur généré au lieu d'utiliser une fonction de rappel. Le moteur s'implémente également de manière asynchrone via le rendement (sinon, il devrait renvoyer une fonction de rappel. En fait, cet exemple ne reflète pas le problème de blocage. le temps est trop court.

Modifions le code


# 之前
yield self.db.user.insert(data)

# 之后
yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 10)

L'application est bloquée ici via tornado.ioloop.IOLoop.instance(). add_timeout. Il s'agit d'une implémentation non bloquante de time.sleep. Si time.sleep est utilisé ici car Tornado est monothread et bloquera l'intégralité de l'application, donc les autres gestionnaires ne pourront pas y accéder

Vous pouvez le voir. après m'être inscrit sur la page d'inscription, j'ai cliqué sur /auth/login pendant la période de blocage et j'ai directement accédé à la page de connexion pour terminer le processus non bloquant


Problèmes de redirection dans des conditions asynchrones

Je rencontre souvent des problèmes lors de l'utilisation de tornado. Je noterai les problèmes rencontrés et les solutions (Merci ici de m'avoir aidé à répondre à mes doutes. pythonistas)
Problème

Je souhaite implémenter une fonction d'utilisateur enregistré. Le framework Web utilise la base de données tornado et mongodb mais une erreur de redirection d'exception se produit lors de l'enregistrement. Collez maintenant le code :

.

Je voulais accéder à la page d'inscription si l'utilisateur saisit le code de vérification de manière incorrecte, mais le problème est que si le code de vérification est incorrect, il continuera à exécuter le code tout en ajoutant self.finish après self. .redirect mettra fin au code, car il y a déjà self.finish dans la fonction self.redirect, il y a deux codes signalant une terminaison anormale
class Register(BaseHandler):
  def get(self):
    self.render_html(&#39;register.html&#39;)

  @tornado.web.aynchronous
  @gen.coroutine
  def post(self):
    username = self.get_argument(&#39;username&#39;)
    email = self.get_argument(&#39;email&#39;)
    password = self.get_argument(&#39;password&#39;)
    captcha = self.get_argument(&#39;captcha&#39;)

    _verify_username = yield self.db.user.find_one({&#39;username&#39;: username})
    if _verify_username:
      self.flash(u&#39;用户名已存在&#39;, &#39;error&#39;)
      self.redirect(&#39;/auth/register&#39;)

    _verify_email = yield self.db.user.find_one({&#39;email&#39;: email})
    if _verify_email:
      self.flash(u&#39;邮箱已注册&#39;, &#39;error&#39;)
      self.redirect(&#39;/auth/register&#39;)

    if captcha and captcha == self.get_secure_cookie(&#39;captcha&#39;).replace(&#39; &#39;,&#39;&#39;):
      self.flash(u&#39;验证码输入正确&#39;, &#39;info&#39;)
    else:
      self.flash(u&#39;验证码输入错误&#39;, &#39;error&#39;)
      self.redirect(&#39;/auth/register&#39;)

    password = haslib.md5(password + self.settings[&#39;site&#39;]).hexdigest()

    profile = {&#39;headimg&#39;: &#39;&#39;, &#39;site&#39;: &#39;&#39;, &#39;job&#39;: &#39;&#39;, &#39;signature&#39;:&#39;&#39;,
          &#39;github&#39;: &#39;&#39;, &#39;description&#39;: &#39;&#39;}
    user_profile = yield self.db.profile.insert(profile)
    user = {&#39;username&#39;: username, &#39;email&#39;: email, &#39;password&#39;: password,
        &#39;timestamp&#39;: time.time(), &#39;profile_id&#39;: str(user_profile)}

    yield self.db.user.insert(user)
    self.set_secure_cookie(&#39;user&#39;, username)
    self.redirect(&#39;/&#39;)
En raison du code de raison ci-dessus, il ne sera pas terminé si le code de vérification est incorrect. , l'utilisateur s'inscrira toujours

2. Solution

Ou
return self.redirect(&#39;/auth/register&#39;)


(1) La réponse donnée par l'utilisateur enthousiaste rsj217 dans segmentdefault
self.redirect(&#39;/auth/register&#39;)
return
self.finish fermera la demande car @ tornado.web.aynchronous dit à tornado que il attendra la demande (lien long). self.redirect équivaut à définir l'attribut location des en-têtes de réponse

(2) La réponse donnée par l'utilisateur enthousiaste Evian dans segmentdefault

Self. terminer, bien sûr, ne sortira pas de la fonction, sinon que se passe-t-il si vous voulez faire quelque chose une fois la demande terminée ?

Résumé

Parce que vous-même. .finish était par erreur Le problème ci-dessus se produit lors de l'utilisation d'une fonction de sautself.redirect définira l'emplacement dans request.headers pour le saut

self.finish fermera la demande, mais le fera ne saute pas de la fonction

Pour plus d'articles liés au framework Tornado de Python implémentant un accès asynchrone non bloquant à la base de données, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn