如果函数里的操作是阻塞的,那么tornado不论使用gen.coroutine 进行装饰还是使用async/await 关键字,都不能让阻塞的函数编程异步的,对于这种情况,可以考虑使用多线程。
tornado.concurrent 提供了run_on_executor装饰器,可以用它来装饰那些无法转为异步的阻塞函数
import tornado.ioloop
import requests
from tornado.web import RequestHandler, Application
from tornado.httpserver import HTTPServer
from tornado.options import options, define
from tornado.httpclient import AsyncHTTPClient
from tornado import gen
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor
define('port', default=8000, help='监听端口')
class HelloHandler(RequestHandler):
executor = ThreadPoolExecutor(4)
@gen.coroutine
def get(self):
url = "http://coolpython.net"
response_code = yield self.fetch_coroutine(url)
self.finish(str(response_code))
@run_on_executor
def fetch_coroutine(self, url):
response = requests.get(url)
return response.status_code
if __name__ == '__main__':
options.parse_command_line()
handlers_routes = [
(r'/', HelloHandler)
]
app = Application(handlers=handlers_routes)
http_server = HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
executor = ThreadPoolExecutor(4) 创建了一个大小为4的线程池,fetch_coroutine方法里,我使用requests 这个http客户端库,它的http请求是同步的。当多个请求同时进入时,fetch_coroutine 会在多线程条件下运行,尽管python有GIL所的问题,但网络请求过程中IO所占的时间是大头,因此多线程条件下,他们看起来仍然像是并发的。
利用多线程,可以解决一部分库不支持异步的问题,但这并没有从根本上解决问题,大量的使用多线程会降低tornado 的性能,因此,它只适合做一些负载比较小的事情,千万不要用它来做那些负载比较高的事情。
QQ交流群: 211426309