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

高洛峰
Libérer: 2017-03-01 13:45:07
original
2464 Les gens l'ont consulté

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
Copier après la connexion

<. 🎜>

2. Installer le moteur

$ pip install motor
Copier après la connexion

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
Copier après la connexion

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
Copier après la connexion

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)
Copier après la connexion

@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)
Copier après la connexion

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;)
Copier après la connexion
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;)
Copier après la connexion


(1) La réponse donnée par l'utilisateur enthousiaste rsj217 dans segmentdefault
self.redirect(&#39;/auth/register&#39;)
return
Copier après la connexion
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 !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!