Tornado是一个异步框架,在异步操作的时候能提升程序的处理性能。但是如果在程序中碰到同步的逻辑,由于GIL的关系,会直接卡死,导致性能急剧下降。

目前对于mongodb以及redis都有比较不错的异步框架,但是对于Mysql,目前的异步框架都不是很成熟。

在实际应用中,由于一开始不是特别了解,在用了Tornado框架的同时,采用了Sqlalchemy来处理Mysql数据。但是由于这部分Mysql操作是同步的,在并发量上去的时候,不能及时返回,大量请求被拒绝。

由于替换Sqlalchemy会造成很大的工作量,经过研究之后发现Tornado有run_on_executor,可以利用线程池达到异步化的目的。

Decorator to run a synchronous method asynchronously on an executor.

The decorated method may be called with a callback keyword argument and returns a future.

The IOLoop and executor to be used are determined by the io_loop and executor attributes of self. To use different attributes, pass keyword arguments to the 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
# 这个并发库在python3自带;在python2需要安装sudo pip install futures
from concurrent.futures import ThreadPoolExecutor
import time
from tornado.options import define, options
define("port", default=8002, help="run on the given port", type=int)

class SleepHandler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(2)

    def get(self):
        tornado.ioloop.IOLoop.instance().add_callback(self.sleep)       # 这样将在下一轮事件循环执行self.sleep
        self.write("when i sleep")

    @run_on_executor
    def sleep(self):
        time.sleep(5)
        print("yes")
        return 5


if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = tornado.web.Application(handlers=[
            (r"/sleep", SleepHandler), ])
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

当然也可以用celery来达到异步的效果,但是不如run_on_executor来的方便