Non-asynchronous blocking mode of tornado

Source: Internet
Author: User
[Optimize the three options for tornado blocking tasks]

1. Optimize blocked tasks to make them run faster. It is often caused by a slow dB query or a complicated upper-layer template. At this time, the primary task is to accelerate these tasks, rather than optimizing the complicated webserver. It can increase the efficiency by 99%.

2. Start a separate thread or process to execute time-consuming tasks. This means that for ioloop, you can enable another thread (or process) to process the off-loading task, so that it can receive other requests instead of blocking.

3. Use asynchronous drivers or library functions to execute tasks, such as gevent and motor.

[Example 1]
import timeimport tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler):    def get(self):        self.write("Hello, world %s" % time.time())class SleepHandler(tornado.web.RequestHandler):    def get(self, n):        time.sleep(float(n))        self.write("Awake! %s" % time.time())application = tornado.web.Application([    (r"/", MainHandler),    (r"/sleep/(\d+)", SleepHandler),])if __name__ == "__main__":    application.listen(8888)    tornado.ioloop.IOLoop.instance().start()

In this way, http: // localhost: 8888/sleep/10 is enabled on a tab page, and http: // localhost: 8888/is accessed on another tab page /, "Hello world" is not printed until the first page is completed. In fact, the first call blocks the ioloop, causing it to fail to respond to the second request.

 

[Example 2 -- non-blocking mode]
from concurrent.futures import ThreadPoolExecutorfrom functools import partial, wrapsimport tornado.ioloopimport tornado.webEXECUTOR = ThreadPoolExecutor(max_workers=4)def unblock(f):    @tornado.web.asynchronous    @wraps(f)    def wrapper(*args, **kwargs):        self = args[0]        def callback(future):            self.write(future.result())            self.finish()        EXECUTOR.submit(            partial(f, *args, **kwargs)        ).add_done_callback(            lambda future: tornado.ioloop.IOLoop.instance().add_callback(                partial(callback, future)))    return wrapperclass SleepHandler(tornado.web.RequestHandler):    @unblock    def get(self, n):        time.sleep(float(n))        return "Awake! %s" % time.time()

The unblock modifier submits the modifier to the thread pool and returns a future. Add a callback function in future and assign control to ioloop.

This callback function will eventually call self. Finish and end the request.

Note: The modifier function must be modified by tornado. Web. asynchronous to avoid calling self. Finish too quickly.

Self. Write is NOT thread-safe, so you should not process future results in the main thread.

When you use the @ tornado. Web. Asynchonous modifier, Tornado will never close the connection by itself, and you need to explicitly close self. Finish ().

[Complete demo]
from concurrent.futures import ThreadPoolExecutorfrom functools import partial, wrapsimport time import tornado.ioloopimport tornado.web  EXECUTOR = ThreadPoolExecutor(max_workers=4)  def unblock(f):     @tornado.web.asynchronous    @wraps(f)    def wrapper(*args, **kwargs):        self = args[0]         def callback(future):            self.write(future.result())            self.finish()         EXECUTOR.submit(            partial(f, *args, **kwargs)        ).add_done_callback(            lambda future: tornado.ioloop.IOLoop.instance().add_callback(                partial(callback, future)))     return wrapper  class MainHandler(tornado.web.RequestHandler):     def get(self):        self.write("Hello, world %s" % time.time())  class SleepHandler(tornado.web.RequestHandler):     @unblock    def get(self, n):        time.sleep(float(n))        return "Awake! %s" % time.time()  class SleepAsyncHandler(tornado.web.RequestHandler):     @tornado.web.asynchronous    def get(self, n):         def callback(future):            self.write(future.result())            self.finish()         EXECUTOR.submit(            partial(self.get_, n)        ).add_done_callback(            lambda future: tornado.ioloop.IOLoop.instance().add_callback(                partial(callback, future)))     def get_(self, n):        time.sleep(float(n))        return "Awake! %s" % time.time()  application = tornado.web.Application([    (r"/", MainHandler),    (r"/sleep/(\d+)", SleepHandler),    (r"/sleep_async/(\d+)", SleepAsyncHandler),])  if __name__ == "__main__":    application.listen(8888)    tornado.ioloop.IOLoop.instance().start()
[Threadpoolexecutor]

The preceding two methods are involved: threadpoolexecutor initialization and submit. For more information, see

class ThreadPoolExecutor(concurrent.futures._base.Executor) |  Method resolution order: |      ThreadPoolExecutor |      concurrent.futures._base.Executor |      __builtin__.object |   |  Methods defined here: |   |  __init__(self, max_workers) |      Initializes a new ThreadPoolExecutor instance. |       |      Args: |          max_workers: The maximum number of threads that can be used to |              execute the given calls. |   |  submit(self, fn, *args, **kwargs) |      Submits a callable to be executed with the given arguments. |       |      Schedules the callable to be executed as fn(*args, **kwargs) and returns |      a Future instance representing the execution of the callable. |       |      Returns: |          A Future representing the given call.

1. max_workers can process the maximum number of threads for a given CILS. What if it exceeds this number ??

2. Submit calls FN (* ARGs, ** kwargs) and returns a future instance.

[Future]
Help on class Future in module concurrent.futures._base:class Future(__builtin__.object) |  Represents the result of an asynchronous computation. |   |  Methods defined here: |   |  __init__(self) |      Initializes the future. Should not be called by clients. |   |  __repr__(self) |   |  add_done_callback(self, fn) |      Attaches a callable that will be called when the future finishes. |       |      Args: |          fn: A callable that will be called with this future as its only |              argument when the future completes or is cancelled. The callable |              will always be called by a thread in the same process in which |              it was added. If the future has already completed or been |              cancelled then the callable will be called immediately. These |              callables are called in the order that they were added.

  

[References]

1. http://lbolla.info/blog/2013/01/22/blocking-tornado

2. http://www.tuicool.com/articles/36ZzA3

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.