Home Backend Development Python Tutorial tornado asynchronous request non-blocking

tornado asynchronous request non-blocking

Oct 17, 2016 pm 01:58 PM

Foreword

Maybe some students are confused: Doesn’t tornado claim to be asynchronous and non-blocking to solve the 10K problem? But I found that it is not that torando is bad, but that you are using it wrong. For example, I recently discovered something: a website is very slow to open the page , the server CPU/memory is normal. The network status is also good. Later, I found that when opening the page, there will be many requests for back-end database access. There is a rest service of mongodb database business api. But its tornado is used incorrectly, step by step Let’s study the problem:


Explanation

The following examples have 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 one is not familiar with the technology, from Logically speaking, the user hopes that his access request will not affect or be affected by other people's 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 5s")

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

If you use a page request or which httpie, curl and other tools to access http://localhost:8000 first /sleep, and then visit http://localhost:8000/justnow. You will find that the request for /jsutnow that could have been returned immediately will be blocked until the /sleep request is completed before returning.


Why is this? Why My request is blocked by /sleep request? If our web requests are usually fast enough we may not realize this problem, but in fact there are often some time-consuming processes, which means that the application is effectively locked until the end of processing.


This is the time for you Have you ever thought of the @tornado.web.asynchronous decorator? But the prerequisite for using this decorator is that you need to perform asynchronous execution for time-consuming execution, such as time.sleep above. Just adding the decorator will have no effect, and it should be noted that Tornado closes the client by default when the function returns. end connection, but when you use the @tornado.web.asynchonous decorator, Tornado will never close the connection by itself, and needs to be closed explicitly by self.finish()


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


#!/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): Or yield tornado.gen.task (tornado.ioloop.ioloop.instance (). Add_timeout, time.time () + 5)

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

Class JustNowHandler (Tor nado.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=[

                                                                                                                                                                                                ) options.port)

tornado.ioloop.IOLoop.instance().start()

There is a new tornado.gen.coroutine decorator. Coroutine is a new decorator after 3.0. The previous method was to use callbacks , or 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 5s")

self.finish()

Callback is used, but the new decorator allows us to achieve the same effect through yield: if you open /sleep and then click /justnow, the justnow request will return immediately without being affected. But with the asynchronous decorator, your Time-consuming functions also need to be executed asynchronously


The examples I just mentioned are all meaningless examples. Here is a useful one: read the mongodb database data, and then write it out line by line on the front end


#! /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 produced by mongodb that supports asynchronous database

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

# Execution of this line still takes time to block. My tt collection has some data and no index

cursor = db.tt.find( ) .sort ([('a', -1)])

# This part of this part will be asynchronous and non -blocking. :

                                                                                                                                                                                                                                                             can raise tornado.web.HTTPError(500, error) .write('

%s

' % i['a'])

                                                                                                                                                                                                                                                                     . 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 Can't this time-consuming thing be asynchronously thrown to a tool for execution without blocking my request? Well, I also thought of: celery, and github just has this thing: tornado-celery

  • Execute the following program First you need 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):


    # tornado. The parameters of gen.Task are: the function to be executed, parameters

                                                                                                                                                                           yield tornado.gen.Task(tasks.sleep.apply_async, args=[5])

                 self.write("when i sleep 5s")

                   .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 the task definition file of celery, including the time.sleep we are talking about Function

    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 (otherwise, how will your task be executed? It is definitely needed A consumer takes it away):


    celery -A tasks worker --loglevel=info

    But the problem here may also be serious: our asynchronous non-blocking depends on celery, or the length of this queue, if the task If there are many, then you need to wait, which is very inefficient. Is there a way to change my synchronous blocking function to asynchronous (or be understood and recognized by tornado's decorator)?


    #!/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 concurrency library In python3, you 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 a local variable not global

    @tornado.web.asynchronous

    @tornado.gen.coroutine

    def get(self):

    # If the asynchronous execution you perform will return a value and continue to be called, you can do this (just for demonstration), otherwise just yield directly

    res = yield self.sleep() I 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()

  • Statement of this Website
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

    Hot AI Tools

    Undresser.AI Undress

    Undresser.AI Undress

    AI-powered app for creating realistic nude photos

    AI Clothes Remover

    AI Clothes Remover

    Online AI tool for removing clothes from photos.

    Undress AI Tool

    Undress AI Tool

    Undress images for free

    Clothoff.io

    Clothoff.io

    AI clothes remover

    Video Face Swap

    Video Face Swap

    Swap faces in any video effortlessly with our completely free AI face swap tool!

    Hot Tools

    Notepad++7.3.1

    Notepad++7.3.1

    Easy-to-use and free code editor

    SublimeText3 Chinese version

    SublimeText3 Chinese version

    Chinese version, very easy to use

    Zend Studio 13.0.1

    Zend Studio 13.0.1

    Powerful PHP integrated development environment

    Dreamweaver CS6

    Dreamweaver CS6

    Visual web development tools

    SublimeText3 Mac version

    SublimeText3 Mac version

    God-level code editing software (SublimeText3)

    How to solve the permissions problem encountered when viewing Python version in Linux terminal? How to solve the permissions problem encountered when viewing Python version in Linux terminal? Apr 01, 2025 pm 05:09 PM

    Solution to permission issues when viewing Python version in Linux terminal When you try to view Python version in Linux terminal, enter python...

    How to teach computer novice programming basics in project and problem-driven methods within 10 hours? How to teach computer novice programming basics in project and problem-driven methods within 10 hours? Apr 02, 2025 am 07:18 AM

    How to teach computer novice programming basics within 10 hours? If you only have 10 hours to teach computer novice some programming knowledge, what would you choose to teach...

    How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? Apr 02, 2025 am 07:15 AM

    How to avoid being detected when using FiddlerEverywhere for man-in-the-middle readings When you use FiddlerEverywhere...

    How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python? How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python? Apr 01, 2025 pm 11:15 PM

    When using Python's pandas library, how to copy whole columns between two DataFrames with different structures is a common problem. Suppose we have two Dats...

    How does Uvicorn continuously listen for HTTP requests without serving_forever()? How does Uvicorn continuously listen for HTTP requests without serving_forever()? Apr 01, 2025 pm 10:51 PM

    How does Uvicorn continuously listen for HTTP requests? Uvicorn is a lightweight web server based on ASGI. One of its core functions is to listen for HTTP requests and proceed...

    How to get news data bypassing Investing.com's anti-crawler mechanism? How to get news data bypassing Investing.com's anti-crawler mechanism? Apr 02, 2025 am 07:03 AM

    Understanding the anti-crawling strategy of Investing.com Many people often try to crawl news data from Investing.com (https://cn.investing.com/news/latest-news)...

    How to dynamically create an object through a string and call its methods in Python? How to dynamically create an object through a string and call its methods in Python? Apr 01, 2025 pm 11:18 PM

    In Python, how to dynamically create an object through a string and call its methods? This is a common programming requirement, especially if it needs to be configured or run...

    See all articles