tornado 的异步原理:
1,Tornado 的异步模型 是由事件驱动以及特定的回调函数(callback)所组成的!
2,tornado 讲特定处理的回调函数与该I/O 事件绑定起来,当该 I/O 事件完成后就调用绑定的回调函数,就可以处理具体的 I/O 事件
3,tornado 利用系统中高效的 I/O 事件轮询机制(epoll on Linux)来进行io 事件完成的检测!
3,无阻塞 I/O +事件驱动+高效轮询方式便组成了 Tornado 的异步模型
tornodo 协程的第一种实现形式(没有使用 epoll 机制):
import time
from tornado.httpclient import HTTPClient,AsyncHTTPClient
def ssync_visit():
old_time = time.time()
#HTTPClient 是tornado 同步访问HTTP客户端
http_client = HTTPClient()
response = http_client.fetch('https://www.baidu.com/') # 阻塞,直到网站请求完成
print(time.time()-old_time) #0.1808912754058838
print(response.body)
def hendle_response(response):
print(response.body)
def async_visit():
old_time = time.time()
# AsyncHTTPClient 是异步访问 HTTP客户端
http_client = AsyncHTTPClient()
# 不会停止,继续往下运行,当对 百度的访问结束之后进行回调
http_client.fetch('www.baidu.com',callback=hendle_response) # 非阻塞
print(time.time() - old_time) #0.0051724910736083984
# ssync_visit() # 同步协程
# async_visit() #异步协程
View Code
tornodo 协程的第二种实现形式(使用了 epoll 机制):
import time
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.httpclient import HTTPClient,AsyncHTTPClient
# 装饰器声明这是个协程函数
@gen.coroutine
def async_visit():
# http_client = AsyncHTTPClient()
# 使用 yield使得代码之中不必要编写回调函数,直接在yield 之后进行书写即可
# response = yield http_client.fetch('https://www.baidu.com/')
# print(response.body)
time.sleep(5)
def func_normal():
print('start to call async_visit')
# 采用了异步形式,不会等待被调用的协程执行完成
# IOLoop.current().spawn_callback(lambda :async_visit()) #0.00044608116149902344
# 同步形式,阻塞当前函数的执行
IOLoop.current().run_sync(lambda :async_visit()) #5.003432750701904
print('end to call async_visit')
old_time = time.time()
func_normal()
print(time.time() - old_time)
View Code
字典的方式处理多个异步调用
from tornado import gen # 引入协程库
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient
# AsyncHTTPClient 相当于封装的套接字 socket
@gen.coroutine
def coroutine_visit():
http_client = AsyncHTTPClient()
dir_response = yield { 'baidu':http_client.fetch('http://www.baidu.com'),
'sina':http_client.fetch('http://www.sina.com'),
'163':http_client.fetch('http://www.163.com')
}
print(dir_response['baidu'].body)
def func_normal():
print('开始调用协程')
IOLoop.current().run_sync(lambda: coroutine_visit())
print('结束协程调用')
old_time = time.time()
func_normal()
print(time.time() - old_time) #0.8374526500701904
View Code
列表的方式实现多个异步调用
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()
View Code
tornado 的缺点:
1,tornado在这里的对数据库的读写完全是同步的。
2,当然如果他作为客户端进行AsyncHTTPClient,当然它也是异步的,它将这个请求挂载到epoll上,数据到达之后进行回调