Tornado是一个异步非堵塞的web框架
但是在遇到数据库的io操作就会发现数据库的io操作是同步执行的
这样将会导致tornado的异步性能急剧下降
经过一系列搜索发现有两种方法可以使这个同步执行变成异步
方法一:使用线程
tornado中有个这样的装饰器run_on_executor
直接翻译过来就是运行在一个执行者上
那么这个执行者是谁呢?答案就是线程
from tornado import httpserver, ioloop
from tornado.web import RequestHandler, Application
from tornado.options import define, options
from tornado.concurrent import run_on_executor
import tornado.options
from concurrent.futures import ThreadPoolExecutor
import time
define('port', default=8000, type=int)
class SleepHandler(RequestHandler):
# 设置线程的并发数量
executor = ThreadPoolExecutor(max_workers=2)
@run_on_executor
def run_sleep(self):
time.sleep(5)
print('finish')
return 10
def get(self, *args, **kwargs):
result = self.run_sleep()
print(result)
self.write('done')
if __name__ == '__main__':
# 注意解析命令行一定要放在最前面执行
tornado.options.parse_command_line()
app = Application([
(r'/sleep', SleepHandler),
])
http_server = httpserver.HTTPServer(app)
http_server.listen(options.port)
ioloop.IOLoop.current().start()
# 执行结果:当调用run_sleep方法的时候,程序并没有等待结果完成,直接执行下面的代码
# 输出一下run_sleep返回结果会发现是一个<Future pending>
通过上面的程序会发现没办法获取到run_sleep的返回结果,可以使用gen.coroutine的方式来的到返回结果
from tornado import httpserver, ioloop, gen
from tornado.web import RequestHandler, Application
from tornado.options import define, options
from tornado.concurrent import run_on_executor
import tornado.options
from concurrent.futures import ThreadPoolExecutor
import time
define('port', default=8000, type=int)
class SleepHandler(RequestHandler):
# 设置线程的并发数量
executor = ThreadPoolExecutor(max_workers=2)
@run_on_executor
def run_sleep(self):
time.sleep(5)
print('finish')
return 10
@gen.coroutine
def get(self, *args, **kwargs):
result = yield self.run_sleep()
self.write(str(result))
self.write('done')
class Indexhandler(RequestHandler):
def get(self, *args, **kwargs):
self.write('index')
if __name__ == '__main__':
# 注意解析命令行一定要放在最前面执行
tornado.options.parse_command_line()
app = Application([
(r'/sleep', SleepHandler),
(r'/index',Indexhandler)
])
http_server = httpserver.HTTPServer(app)
http_server.listen(options.port)
ioloop.IOLoop.current().start()
方法二:通过进程的方式
from tornado import httpserver, ioloop, gen
from tornado.web import RequestHandler, Application
from tornado.options import define, options
import tornado.options
from concurrent.futures import ProcessPoolExecutor
import time
define('port', default=8000, type=int)
# 并发进程数
executor = ProcessPoolExecutor(max_workers=2)
def run_sleep():
time.sleep(5)
return 'sleep_done'
class SleepHandler(RequestHandler):
# @gen.coroutine
def get(self, *args, **kwargs):
#把要执行的函数提交到进程中
executor.submit(run_sleep)
if __name__ == '__main__':
tornado.options.parse_command_line()
app = Application([
(r'/sleep', SleepHandler)
])
http_server = httpserver.HTTPServer(app)
http_server.listen(options.port)
ioloop.IOLoop.current().start()
获取异步执行的结果与方法一相同,使用gen.coroutine