Python的Tornado框架实现异步非阻塞访问数据库的示例


Posted in Python onJune 30, 2016

tornado即是一个http非阻塞服务器, 就要用起来, 我们将用到tornado框架 ,mongodb数据库 以及motor(mongodb的异步驱动).来简单实现tornado的非阻塞功能.

其他环境支持的下载与安装

1.安装mongodb

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

2.安装motor

$ pip install motor

非阻塞

# 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

首先在配置文件中连接数据库, client.db_name中 db_name就是数据库的名称

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

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

添加db()并使用property装饰,像属性一样访问数据库.

# 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装饰使函数非阻塞, 返回一个生成器, 而不用在使用回调函数. motor也通过yield 实现异步(不然还得返回一个回调函数). 其实这个例子反映不了阻塞问题关键是时间太短.
我们修改一下代码

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

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

这里通过tornado.ioloop.IOLoop.instance().add_timeout阻塞应用, 这是time.sleep的非阻塞实现, 如果这里使用time.sleep因为是tornado是单线程会阻塞整个应用所以别的handler也无法访问.
可以看到我在注册页面注册后,在阻塞期间点击/auth/login直接就访问了login页完成非阻塞.

异步下的redirect问题
在使用tornado的时候常常遇到一些问题, 特将遇到的问题和解决的方法写出来(这里的感谢一下帮我解答疑惑的pythonista们)

1.问题

我想要实现一个注册用户功能, web框架使用tornado数据库使用mongodb但在注册时出现Exception redirect的错误. 现贴下代码:

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('/')

本想如果用户验证码输入出错就跳转到注册页面, 但问题是验证码出错也会继续执行一下代码. 虽然在self.redirect后加上self.finish会终止代码,但是因为self.redirect 函数内已有self.finish所以出现了两次报出异常终止的代码.
因为以上原因代码不会被终结, 验证码出错用户还是会注册.

2.解决方案

return self.redirect('/auth/register')


self.redirect('/auth/register')
return

(1)segmentdefault中热心用户rsj217给出的答案
self.finish 会关掉请求, 因为@tornado.web.aynchronous告诉tornado会一直等待请求(长链接). self.redirect等于设置了response的headers的location属性.

(2)segmentdefault中热心用户依云给出的答案
self.finish当然不会跳出函数, 不然请求结束之后还想做些事情怎么办呢.

3.总结

因为错把self.finish当做跳出函数出现了以上的问题

  • self.redirect会在request.headers 里设置location用于跳转
  • self.finish会关掉请求, 但不会跳出函数
Python 相关文章推荐
python实现sublime3的less编译插件示例
Apr 27 Python
python 二分查找和快速排序实例详解
Oct 13 Python
对python过滤器和lambda函数的用法详解
Jan 21 Python
python 实现将多条曲线画在一幅图上的方法
Jul 07 Python
python变量的存储原理详解
Jul 10 Python
django如何通过类视图使用装饰器
Jul 24 Python
Pandas+Matplotlib 箱式图异常值分析示例
Dec 09 Python
Django 设置admin后台表和App(应用)为中文名的操作方法
May 10 Python
pyCharm 设置调试输出窗口中文显示方式(字符码转换)
Jun 09 Python
python学习笔记之多进程
Aug 06 Python
Python 整行读取文本方法并去掉readlines换行\n操作
Sep 03 Python
对象析构函数__del__在Python中何时使用
Mar 22 Python
Python的Tornado框架实现图片上传及图片大小修改功能
Jun 30 #Python
举例讲解Python中metaclass元类的创建与使用
Jun 30 #Python
在Python中定义和使用抽象类的方法
Jun 30 #Python
Python中functools模块的常用函数解析
Jun 30 #Python
深入浅析Python中join 和 split详解(推荐)
Jun 30 #Python
Python列出一个文件夹及其子目录的所有文件
Jun 30 #Python
django之常用命令详解
Jun 30 #Python
You might like
用php实现批量查询清除一句话后门的代码
2008/01/20 PHP
『PHP』PHP截断函数mb_substr()使用介绍
2013/04/22 PHP
使用PHP连接多种数据库的实现代码(mysql,access,sqlserver,Oracle)
2016/12/21 PHP
PHP 访问数据库配置通用方法(json)
2018/05/20 PHP
jQuery 解析xml文件
2009/08/09 Javascript
ext 列表页面关于多行查询的办法
2010/03/25 Javascript
jquery带下拉菜单和焦点图代码分享
2015/08/24 Javascript
Bootstrap轮播插件简单使用方法介绍
2016/06/21 Javascript
微信+angularJS的SPA应用中用router进行页面跳转,jssdk校验失败问题解决
2016/09/09 Javascript
小程序实现抽奖动画
2020/04/16 Javascript
JavaScript常见事件对象与操作实例总结
2019/01/05 Javascript
js实现时间日期校验
2020/05/26 Javascript
[03:42]2014DOTA2西雅图国际邀请赛7月9日TOPPLAY
2014/07/09 DOTA
Python中的map、reduce和filter浅析
2014/04/26 Python
Python的Flask站点中集成xhEditor文本编辑器的教程
2016/06/13 Python
Python实现图片滑动式验证识别方法
2017/11/09 Python
利用Python实现Shp格式向GeoJSON的转换方法
2019/07/09 Python
python中的线程threading.Thread()使用详解
2019/12/17 Python
python函数调用,循环,列表复制实例
2020/05/03 Python
总结python 三种常见的内存泄漏场景
2020/11/20 Python
HTML+CSS3模拟心的跳动实例代码
2017/09/05 HTML / CSS
美国一家专业的太阳镜网上零售商:Solstice太阳镜
2016/07/25 全球购物
苹果Mac升级:MacSales.com
2017/11/20 全球购物
菲律宾领先的在线时尚商店:Zalora菲律宾
2018/02/08 全球购物
印度尼西亚电子产品购物网站:Kliknklik
2018/06/05 全球购物
银行领导证婚词
2014/01/11 职场文书
大学校园生活自我鉴定
2014/01/13 职场文书
平民服装店创业计划书
2014/01/17 职场文书
红旗方阵解说词
2014/02/12 职场文书
圣诞节活动策划方案
2014/06/09 职场文书
优秀教育工作者事迹材料
2014/12/24 职场文书
外国人来华邀请函
2015/01/31 职场文书
想创业成功,需要掌握这些要点
2019/12/06 职场文书
详解Js模块化的作用原理和方案
2021/04/29 Javascript
python实现Nao机器人的单目测距
2021/09/04 Python
浅谈TypeScript 索引签名的理解
2021/10/16 Javascript