Example of implementing asynchronous non-blocking access to the database using Python Tornado framework, pythontornado
Tornado is an http non-blocking server. We will use the tornado framework, mongodb database, and motor (asynchronous driver of mongodb) to implement tornado's non-blocking function.
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.pyimport osimport motorfrom handlers import index, authBASE_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. In client. db_name, db_name is the database name.
# handlers/__init__.pyclass BaseHandler(tornado.web.RequestHandler, TemplateRendering): def initialite(self): ... @property def db(self): return self.application.db
Add db () and use the property decoration to access the database like the property.
# auth.pyimport os import time import tornado.webfrom tornado import genfrom . import BaseHandlerclass 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. the coroutine decoration makes the function non-blocking and returns a generator instead of using the callback function. motor also implements Asynchronization through yield (otherwise, a callback function will 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) # After yield tornado. gen. task (tornado. ioloop. IOLoop. instance (). add_timeout, time. time () + 10)
Tornado is used here. ioloop. IOLoop. instance (). add_timeout blocks the application. This is time. non-blocking implementation of sleep, if time is used here. sleep because it is tornado and a single thread will block the entire application, other handler cannot access it.
You can see that after I register on the registration page, click/auth/login during blocking to directly access the login page to complete non-blocking.
Redirect in asynchronous mode
When using tornado, I often encounter some problems. I would like to write out the problems and solutions (here I would like to thank pythonista for helping me solve these problems)
1. Problem
I want to implement a user registration function. The web framework uses the tornado database to use mongodb, but the Exception redirect error occurs during registration. The following code is posted:
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'user name already exists ', 'error') self. redirect ('/auth/register') _ verify_email = yield self. db. user. find_one ({'email ': email}) if _ verify_email: self. flash (u'email registered ', 'error') self. redirect ('/auth/register') if captcha and captcha = self. get_secure_cookie ('captcha '). replace ('',''): self. flash (u'verification code entered correctly ', 'info') else: self. flash (u'verification code input error', 'error') self. redirect ('/auth/register') password = haslib. md5 (password + self. settings ['SITE']). hexdigest () profile = {'uploadmg ': '', '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 ('/')
If the user verification code is entered incorrectly, the registration page will be displayed. However, if the verification code is incorrect, the system will continue to execute the code. although in self. add self. finish will terminate the code, but because of self. the redirect function already contains self. therefore, the code for abnormal termination is reported twice.
The code will not be terminated because of the above reasons, and the user will still register if the verification code is incorrect.
2. Solution
return self.redirect('/auth/register')
Or
self.redirect('/auth/register')return
(1) answer provided by rsj217, an enthusiastic user in segmentdefault
Self. finish closes the request because @ tornado. web. aynchronous tells tornado to wait for the request (long link). self. redirect equals to setting the location attribute of headers of response.
(2) answers provided by Yiyun, enthusiastic users in segmentdefault
Self. finish certainly does not jump out of the function. Otherwise, what else do I want to do after the request ends.
3. Summary
The above problem occurs because self. finish is taken out of the function by mistake.
- Self. redirect will set location in request. headers for redirect
- Self. finish will close the request, but will not jump out of the Function