Tornado asynchronous request non-blocking

Source: Internet
Author: User
Objective

Perhaps a classmate is puzzled: Tornado not advertised asynchronous non-blocking solve 10K problem? But I found not torando bad, but you use the wrong. For example, recently found a thing: a Web site open page is slow, the server cpu/memory is OK. The network is also in good condition. Later found that the open page would have a lot of requests for back-end database access, and there is a MongoDB database service API for rest services. But its tornado is wrong, step-by-step to study the problem:


Description

The following examples have 2 URLs, one is a time-consuming request, one is a request that can or should be returned immediately, I think even if a person is not familiar with the technology, from the point of view of the user, he hopes that his visit will not affect the request and will not be affected by other people's request


#!/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 5s")

Class Justnowhandler (Tornado.web.RequestHandler):

def get (self):

Self.write ("I hope just now")

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

If you use a page request or use a tool such as Httpie,curl to access Http://localhost:8000/sleep first, then visit Http://localhost:8000/justnow. You will find that you can return immediately. The Jsutnow request will be blocked until the/sleep request is finished before returning.


Why is this? Why is my request blocked by a/sleep request? If our web requests are usually fast enough we may not be aware of this problem, but in fact there are often time-consuming processes that mean that the application is effectively locked until the processing is complete.


Is it time you remembered @tornado.web.asynchronous this decorator? But the premise of using this decorator is that you need to take time to execute asynchronously, such as the above time.sleep, you just add the adorner is not functional, and it is important to note that tornado by default when the function processing returns, the client's connection is closed. But when you use the @tornado.web.asynchonous adorner, Tornado never close the connection yourself, and you need an explicit self.finish () to close


Most of our functions are blocked, such as the above Time.sleep actually tornado 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 5s")

Class Justnowhandler (Tornado.web.RequestHandler):

def get (self):

Self.write ("I hope just now")

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's a new tornado.gen.coroutine decorator, and Coroutine is the decorator that was added after 3.0. The previous approach was to use a callback, or see 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 5s")

Self.finish ()

Callback is used, but the new adorner allows us to achieve the same effect with yield: After you open/sleep and then click/justnow, Justnow requests are immediately returned unaffected. But with the asynchronous decorator, your time-consuming function also needs to perform asynchronous


What you just said is meaningless examples, the following is a bit of a use: Read the MongoDB database data, and then the front-end press the line to write out


#!/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 MongoDB-produced Python driver 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 a cursor in 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 line to execute or block, my TT collection has some data and no index

cursor = Db.tt.find (). Sort ([(' A ',-1)])

# This part asynchronously non-blocking execution two does not affect other page requests

while (yield Cursor.fetch_next):

message = Cursor.next_object ()

Self.write ('

  • %s
  • '% message[' a '])

    Self.write (")

    Self.finish ()

    def _on_response (self, message, error):

    If error:

    Raise Tornado.web.HTTPError ($, error)

    Elif message:

    For i in message:

    Self.write ('

  • %s
  • '% i[' a '])

    Else

    Self.write (")

    Self.finish ()

    Class Justnowhandler (Basehandler):

    def get (self):

    Self.write ("I hope just now")

    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 suggests why this time-consuming thing cannot be asynchronously dropped to a tool to execute without blocking my request? Well, I also thought: celery, just GitHub has this thing: tornado-celery


    Execute the following program first you want to 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 parameters of the Tornado.gen.Task are: the function to be executed, the parameter

    Yield Tornado.gen.Task (Tasks.sleep.apply_async, args=[5])

    Self.write ("When I Sleep 5s")

    Self.finish ()

    Class Justnowhandler (Tornado.web.RequestHandler):

    def get (self):

    Self.write ("I hope just now")

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

    The task is a celery-defined file that contains the functions we call time.sleep.


    Import time

    From celery import celery

    celery = celery ("Tasks", broker= "amqp://guest:guest@localhost: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 the Celelry worker (or else how do you do it?) must have a consumer to take away):


    Celery-a Tasks worker--loglevel=info

    But the problem here can also be serious: our asynchronous non-blocking relies on celery, or the length of the queue, and if the task is a lot then it needs to wait and be inefficient. Is there a way to make my sync blocking function asynchronous (or tornado to understand and recognize it)?


    #!/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 in Python3 comes with python2 need to install sudo pip install futures

    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 that local variables are not global

    @tornado. web.asynchronous

    @tornado. Gen.coroutine

    def get (self):

    # If you execute the asynchronous return value will be called again (just for demonstration), otherwise direct yield is OK

    res = yield Self.sleep ()

    Self.write ("When I sleep%s 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")

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

  • Related Article

    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.