以前在公司的一个模块,须要从另外一处url取得数据,我使用了Python的一个很著名的lib,叫作requests。可是这样作极大的下降了程序的性能,由于tornado是单线程的,它使用了所谓的reactor模式,底层使用epoll监听每一个tcp链接,上层再通过封装,接受HTTP请求。因此,tornad其实是单线程的。html
在实际的场景中,常常采用nginx反向代理的模式,而后服务器开启多个tornado进程,接受nginx发送过来的请求。react
刚才的问题主要是,由于requests是阻塞的,因此当我发出一个post请求,整个tornado进程就阻塞了,此时该进程不能接受任何的其余请求。nginx
想一想咱们的服务器总共才十几个tornado进程,可能要应对上千的并发量,因此阻塞一个进程对咱们是巨大的损失。web
tornado内置了异步的模块,例如AsyncHttpClient,它的使用以下:数据库
class MainHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): http = tornado.httpclient.AsyncHTTPClient() http.fetch("http://friendfeed-api.com/v2/feed/bret", callback=self.on_response) def on_response(self, response): if response.error: raise tornado.web.HTTPError(500) json = tornado.escape.json_decode(response.body) self.write("Fetched " + str(len(json["entries"])) + " entries " "from the FriendFeed API") self.finish()
那么,tornado的gen是怎么回事? 能够看到,上面的代码中使用了回调函数,可是回调函数有一个致命的问题,若是逻辑很是复杂,那么咱们的程序可能嵌套多层回调,形成所谓的“回调地狱”。json
事实上,tornado的gen模块,就是为了改善这一问题。例如:api
class GenAsyncHandler(RequestHandler): @gen.coroutine def get(self): http_client = AsyncHTTPClient() response = yield http_client.fetch("http://example.com") do_something_with_response(response) self.render("template.html")
从上面能够看出,gen模块的最大做用,就是将异步代码的编写进行改进,使其看起来像同步。服务器
上面的代码执行时,遇到yield后面的阻塞调用则暂停,而后去执行其余请求,等该数据返回时,再继续处理这里。并发
这样就防止了一个IO操做阻塞整个进程。异步
在实际应用中,对于可能阻塞的操做(例如查询量较大的数据库查询),最好使用异步。