tornado is an http non-blocking server. To use it, we will use the tornado framework, mongodb database and motor (mongodb's asynchronous driver) to simply implement the non-blocking function of tornado.
Download and installation supported by other environments
1. Install mongodb
$ sudo apt-get install update $ sudo apt-get install mongodb
2. Install motor
$ pip install motor
non-blocking
# 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
First connect to the database in the configuration file, db_name in client.db_name is the name of the database
# handlers/__init__.py class BaseHandler(tornado.web.RequestHandler, TemplateRendering): def initialite(self): ... @property def db(self): return self.application.db
Add db() and use property Decoration, access the database like a 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 decoration makes the function non-blocking, returning a generator instead of using a callback function. motor Asynchronous is also implemented through yield (otherwise a callback function must be returned). In fact, this example does not reflect the blocking problem. The key is that the time is too short.
Let’s modify the code
# 之前 yield self.db.user.insert(data) # 之后 yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 10)
The application is blocked here through tornado.ioloop.IOLoop.instance().add_timeout, which is a non-blocking implementation of time.sleep. If time.sleep is used here, because tornado is a single thread, it will block the entire application, so other handlers It is also inaccessible.
You can see that after registering on the registration page, I clicked /auth/login during the blocking period and directly accessed the login page to complete the non-blocking process.
Redirect problem under asynchronous
I often encounter some problems when using tornado, so I will write down the problems encountered and the solutions (I would like to thank the pythonistas who helped me answer my doubts)
1. Question
I want to implement a registered user function. The web framework uses tornado database and mongodb but an Exception redirect error occurs during registration. Now paste the code:
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('/')
I originally wanted to jump to the registration page if the user enters the verification code incorrectly, but the problem is that if the verification code is incorrect, the code will continue to be executed. Although self is added after self.redirect. finish will terminate the code, but because there is already self.finish in the self.redirect function, there are two abnormal termination codes.
Because of the above reasons, the code will not be terminated, and users will still register if the verification code is wrong.
2.Solution
return self.redirect('/auth/register')
or
self.redirect('/auth/register') return
(1) The answer given by the enthusiastic user rsj217 in segmentdefault
self.finish will turn off the request, because @tornado.web.aynchronous tells tornado that it will wait for the request (long link). self. Redirect is equivalent to setting the location attribute of the response headers.
(2) The answer given by the enthusiastic user Evian in segmentdefault
self.finish will of course not jump out of the function, otherwise you will want to do something after the request is completed. What to do.
3. Summary
The above problem occurs because self.finish is mistakenly regarded as a jump-out function
self.redirect will Set location in request.headers for jump
self.finish will close the request, but will not jump out of the function
More Python's Tornado framework implements asynchronous non-blocking access to the database related articles Please pay attention to PHP Chinese website!