同步异步I/O客户端python
from tornado.httpclient import HTTPClient,AsyncHTTPClient def ssync_visit(): http_client = HTTPClient() response = http_client.fetch('www.baidu.com') # 阻塞,直到网站请求完成 print(response.body) def hendle_response(response): print(response.body) def async_visit(): http_client = AsyncHTTPClient() http_client.fetch('www.baidu.com',callback=hendle_response) # 非阻塞 async_visit()
协程mysql
一、编写协程函数git
from tornado import gen # 引入协程库 from tornado.httpclient import AsyncHTTPClient @gen.coroutine def coroutine_visit(): http_client = AsyncHTTPClient() response = yield http_client.fetch('www.baidu.com') print(response.body)
二、调用协程函数github
因为Tornado协程基于python的yield关键字实现,因此不能调用普通函数同样调用协程函数web
协程函数可经过如下三种方式调用sql
下面是一个经过协程函数调用协程函数的例子mongodb
@gen.coroutine def outer_coroutine(): print('开始调用另外一个协程') yield coroutine_visit() print('outer_coroutine 调用结束')
outer_coroutine和coroutine_visit都是协程函数,他们之间能够经过yield关键字进行调用
IOLoop 是Tornado的主事件循环对象,Tornado程序经过它监听外部客户端的访问请求,并执行相应的操做,当程序还没有进入IOLoop的runing状态时,能够经过run_sync()函数调用协程函数,好比:
from tornado import gen # 引入协程库 from tornado.ioloop import IOLoop from tornado.httpclient import AsyncHTTPClient @gen.coroutine def coroutine_visit(): http_client = AsyncHTTPClient() response = yield http_client.fetch('http://www.baidu.com') print(response.body) def func_normal(): print('开始调用协程') IOLoop.current().run_sync(lambda: coroutine_visit()) print('结束协程调用') func_normal()
本例中run_sync()函数将当前函数的执行进行阻塞,直到被调用的协程执行完成数据库
Tornado 要求协程函数在IOloop的running状态才能被调用,只不过run_sync函数自动完成了启动,中止IOLoop的步骤,他的实现逻辑为:启动IOLoop-调用被lambda封装的协程函数-中止IOLoop编程
当tornado程序已经处于running 状态时协程的调用以下:网络
def func_normal(): print('开始调用协程') IOLoop.current().spawn_callback(coroutine_visit) print('结束协程调用') func_normal()
开始调用协程
结束协程调用
本例中spawn_callback函数不会等待被调用的协程执行完成,而协程函数将会由IOLoop在合适的时机进行调用,而且spawn_callback函数没有提供电泳返回值的方法,因此hi能用该函数调用没有返回值的协程函数
三、在协程中调用阻塞函数
在协程中直接调用阻塞函数会影响协程自己的性能,因此tornado提供了在协程中利用线程池调度阻塞函数,从而不影响协程自己继续执行的方法,实例代码以下:
from concurrent.futures import ThreadPoolExecutor from tornado import gen thread_pool = ThreadPoolExecutor(2) def mySleep(count): import time for i in range(count): time.sleep(1) @gen.coroutine def call_backing(): print('开始调用当前函数') yield thread_pool.submit(mySleep,10) print('结束调用') call_backing()
四、在协程中的等待多个异步调用
tornado容许在协程中用一个yield关键字等待多个异步调用,只需把这些调用用列表或字典的方式传递给yield关键字便可
实例以下:
from tornado import gen # 引入协程库 from tornado.ioloop import IOLoop from tornado.httpclient import AsyncHTTPClient @gen.coroutine def coroutine_visit(): http_client = AsyncHTTPClient() list_response = yield [http_client.fetch('http://www.baidu.com'), http_client.fetch('http://www.sina.com'), http_client.fetch('http://www.163.com') ] for response in list_response: print(response.body) def func_normal(): print('开始调用协程') IOLoop.current().run_sync(lambda: coroutine_visit()) print('结束协程调用') func_normal()
字典同理,再也不演示
Tornado 网站
异步化,协程化
当大量客户端高并发请求场景出现时,须要用到两种方式改变同步的处理请求流程
一、异步化
from tornado import web,httpclient import tornado class MainHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): http = tornado.httpclient.AsyncHTTPClient() http.fetch('http://www.baidu.com',callback=self.on_response) def on_response(self,response): if response.error: raise tornado.web.HTTPError(500) self.write(response.body) self.finish()
用@tornado.web.asynchronous 定义HTTP访问处理函数get(),当get函数返回时对该访问的请求还没有完成,因此tornado没法发送响应给客户端,只有随后的回掉函数中的finsh函数被调用时,tornado才知道本次处理已经完成,能够发送响应给客户端
异步虽然提升了并发能力,可是编程方法更繁琐
二、协程化
tornado 协程结合同步异步的优势,
import tornado.web import tornado.httpclient class MainHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): http = tornado.httpclient.AsyncHTTPClient() response = yield http.fetch('http://www.baidu.com') self.write(response.body)
用tornado.gen.coroutine装饰MainHandler的get(),post()函数
使用异步对象处理耗时操做,好比AsyncHTTPClient
调用yield关键字获取异步对象的处理结果
下各项同步(阻塞)的,若是在 tornado 中按照以前的方式只用它们,就是把 tornado 的非阻塞、异步优点削减了。
解决方法
tornado.gen.sleep()
或者tornado.ioloop.IOLoop.instance().add_timeout
greenlet-tornado 能够实现用专门的库来实现tornado 的异步而不使用装饰器的异步