Tornado asynchronous request non-blocking

Source: Internet
Author: User
Tags sleep function
Some may be confused: Isn't tornado advertised that asynchronous non-blocking solves the 10 k problem? However, I found that not torando is not good, but you used it wrong. For example, you recently discovered one thing: a certain network

Preface

Some may be confused: Isn't tornado advertised that asynchronous non-blocking solves the 10 k problem? But I found that not torando is bad, but you used it wrong. for example, a website is slow to open pages, and the CPU/memory of the server is normal. the network status is also good. later, I found that there were a lot of requests to access the back-end database, and there was a rest service for the MongoDB Database Service API. however, its tornado is wrong, and the problem is studied step by step:

 

Description

In the following example, there are two URLs: one is a time-consuming request, and the other is a request that can or needs to be returned immediately. I think even if I am not familiar with the technology, in principle, he hopes that his access requests will not be affected and will not be affected by other users' requests.

 

#! /Bin/ENV Python

Import tornado. httpserver

Import tornado. ioloop

Import tornado. Options

Import tornado. Web

Import tornado. httpclient

Import time

From tornado. Options import define, options

Define ("Port", default = 8000, help = "run on the given port", type = int)

Class sleephandler (tornado. Web. requesthandler ):

Def get (Self ):

Time. Sleep (5)

Self. Write ("when I sleep 5 S ")

Class justnowhandler (tornado. Web. requesthandler ):

Def get (Self ):

Self. Write ("I hope just now see you ")

If _ name _ = "_ main __":

Tornado. Options. parse_command_line ()

APP = tornado. Web. Application (handlers = [

(R "/sleep", sleephandler), (R "/justnow", justnowhandler)])

Http_server = tornado. httpserver. httpserver (APP)

Http_server.listen (options. Port)

Tornado. ioloop. ioloop. instance (). Start ()

Assume that you access http: // localhost: 8000/sleep first by using a page request or tools such as httpie and curl, and then access http: // localhost: 8000/justnow. you will find that the/jsunow request that can be returned immediately will be blocked until the/sleep request is complete.

 

Why? Why is my request blocked by/sleep requests? If our Web requests are fast enough at ordinary times, we may not be aware of this problem, but in fact there are often some time-consuming processes, which means that the application is effectively locked until the processing ends.

 

Does this remind you of @ tornado. Web. asynchronous? However, the premise of using this decorator is that you need to execute asynchronous execution for time-consuming execution, such as the preceding time. sleep, you just add the modifier does not work, and it should be noted that tornado closes the client connection when function processing returns by default, but when you use @ tornado. web. when Asynchonous decorator is used, Tornado will never close the connection by itself. close finish ()

 

Most of our functions are congested. For example, the above time. Sleep actually tornado has an asynchronous implementation:

 

#! /Bin/ENV Python

Import tornado. httpserver

Import tornado. ioloop

Import tornado. Options

Import tornado. Web

Import tornado. gen

Import tornado. httpclient

Import tornado. Concurrent

Import tornado. ioloop

Import time

From tornado. Options import define, options

Define ("Port", default = 8000, help = "run on the given port", type = int)

Class sleephandler (tornado. Web. requesthandler ):

@ Tornado. Web. asynchronous

@ Tornado. gen. coroutine

Def get (Self ):

Yield tornado. gen. task (tornado. ioloop. ioloop. instance (). add_timeout, time. Time () + 5)

Self. Write ("when I sleep 5 S ")

Class justnowhandler (tornado. Web. requesthandler ):

Def get (Self ):

Self. Write ("I hope just now see you ")

If _ name _ = "_ main __":

Tornado. Options. parse_command_line ()

APP = tornado. Web. Application (handlers = [

(R "/sleep", sleephandler), (R "/justnow", justnowhandler)])

Http_server = tornado. httpserver. httpserver (APP)

Http_server.listen (options. Port)

Tornado. ioloop. ioloop. instance (). Start ()

Here is a new tornado. gen. coroutine, which is a new coroutine after 3.0. The previous method is to use callback. Let's look at my example:

 

Class sleephandler (tornado. Web. requesthandler ):

@ Tornado. Web. asynchronous

Def get (Self ):

Tornado. ioloop. ioloop. instance (). add_timeout (Time. Time () + 5, callback = self. on_response)

Def on_response (Self ):

Self. Write ("when I sleep 5 S ")

Self. Finish ()

Callback is used, but the new decorator allows us to achieve the same effect through yield: You click/justnow after opening/sleep, and the requests of justnow are immediately returned and will not be affected. however, with the asynchronous decorator, your time-consuming functions also need to be asynchronous.

 

The above are all meaningless examples. The following is a bit useful: Read the MongoDB database data, and then write the data in the front end by row.

 

#! /Bin/ENV Python

Import tornado. httpserver

Import tornado. ioloop

Import tornado. Options

Import tornado. Web

Import tornado. gen

Import tornado. httpclient

Import tornado. Concurrent

Import tornado. ioloop

Import time

# A python driver for MongoDB that supports asynchronous Databases

Import Motor

From tornado. Options import define, options

Define ("Port", default = 8000, help = "run on the given port", type = int)

# DB is actually the cursor of the Test Database

DB = motor. motorclient (). open_sync (). Test

Class sleephandler (basehandler ):

@ Tornado. Web. asynchronous

@ Tornado. gen. coroutine

Def get (Self ):

# It takes time for this row to be blocked. My TT set has some data and has no index.

Cursor = dB. tt. Find (). Sort ([('A',-1)])

# The asynchronous non-blocking execution of this branch does not affect other page requests

While (yield cursor. fetch_next ):

Message = cursor. next_object ()

Self. Write ('<li> % S </LI>' % message ['a'])

Self. Write ('</ul> ')

Self. Finish ()

Def _ on_response (self, message, error ):

If error:

Raise tornado. Web. httperror (500, error)

Elif message:

For I in message:

Self. Write ('<li> % S </LI>' % I ['a'])

Else:

Self. Write ('</ul> ')

Self. Finish ()

Class justnowhandler (basehandler ):

Def get (Self ):

Self. Write ("I hope just now see you ")

If _ name _ = "_ main __":

Tornado. Options. parse_command_line ()

APP = tornado. Web. Application (handlers = [

(R "/sleep", sleephandler), (R "/justnow", justnowhandler)])

Http_server = tornado. httpserver. httpserver (APP)

Http_server.listen (options. Port)

Tornado. ioloop. ioloop. instance (). Start ()

A colleague suggested why this time-consuming item cannot be asynchronously thrown to a tool for execution without blocking my requests? Okay, I also thought of celery. GitHub has this thing: tornado-celery.

 

To execute the following program, you must first install rabbitmq and celery:

 

#! /Bin/ENV Python

Import tornado. httpserver

Import tornado. ioloop

Import tornado. Options

Import tornado. Web

Import tornado. gen

Import tornado. httpclient

Import tcelery, tasks

Import time

From tornado. Options import define, options

Define ("Port", default = 8000, help = "run on the given port", type = int)

Tcelery. setup_nonblocking_producer ()

Class sleephandler (tornado. Web. requesthandler ):

@ Tornado. Web. asynchronous

@ Tornado. gen. coroutine

Def get (Self ):

# The Tornado. gen. Task parameter is the function to be executed. The Parameter

Yield tornado. gen. task (tasks. Sleep. apply_async, argS = [5])

Self. Write ("when I sleep 5 S ")

Self. Finish ()

Class justnowhandler (tornado. Web. requesthandler ):

Def get (Self ):

Self. Write ("I hope just now see you ")

If _ name _ = "_ main __":

Tornado. Options. parse_command_line ()

APP = tornado. Web. Application (handlers = [

(R "/sleep", sleephandler), (R "/justnow", justnowhandler)])

Http_server = tornado. httpserver. httpserver (APP)

Http_server.listen (options. Port)

Tornado. ioloop. ioloop. instance (). Start ()

Task is a celery task definition file, which contains the time. Sleep function.

 

Import time

From celery import celery

Celery = celery ("Tasks", broker = "amqp: // Guest: [email protected]: 5672 ")

Celery. conf. celery_result_backend = "amqp"

@ Celery. Task

Def sleep (seconds ):

Time. Sleep (float (seconds ))

Return seconds

If _ name _ = "_ main __":

Celery. Start ()

Then start celelry worker (or how do you execute your task? Must be removed by a consumer ):

 

Celery-A tasks worker -- loglevel = info

However, the problem here may also be very serious: Our asynchronous non-blocking depends on celery, or the length of this queue. If there are many tasks, we need to wait and the efficiency is very low. is there a way to convert my synchronous blocking function to asynchronous (or be understood and recognized by tornado decorators?

 

#! /Bin/ENV Python

Import tornado. httpserver

Import tornado. ioloop

Import tornado. Options

Import tornado. Web

Import tornado. httpclient

Import tornado. gen

From tornado. Concurrent import run_on_executor

# This concurrent library is included in python3 and needs to install sudo Pip install futures in python2.

From concurrent. Futures import threadpoolexecutor

Import time

From tornado. Options import define, options

Define ("Port", default = 8000, help = "run on the given port", type = int)

Class sleephandler (tornado. Web. requesthandler ):

Executor = threadpoolexecutor (2)

# Executor is a local variable rather than a global variable.

@ Tornado. Web. asynchronous

@ Tornado. gen. coroutine

Def get (Self ):

# If the asynchronous method you run will return the value to be called again, you can (just for demonstration). Otherwise, you can directly use yield.

Res = yield self. Sleep ()

Self. Write ("when I sleep % s" % res)

Self. Finish ()

@ Run_on_executor

Def sleep (Self ):

Time. Sleep (5)

Return 5

Class justnowhandler (tornado. Web. requesthandler ):

Def get (Self ):

Self. Write ("I hope just now see you ")

If _ name _ = "_ main __":

Tornado. Options. parse_command_line ()

APP = tornado. Web. Application (handlers = [

(R "/sleep", sleephandler), (R "/justnow", justnowhandler)])

Http_server = tornado. httpserver. httpserver (APP)

Http_server.listen (options. Port)

Tornado. ioloop. ioloop. instance (). Start ()

Tornado asynchronous request non-blocking

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.