Tornado使用-简介

1.什么是Tornado
Tornado是一个python web框架,和一个异步网络通信库。
因为它的非阻塞网络IO,可同时支撑万级别的连接请求。
适用于长轮询,全双工websocket通信。

2.主要模块
1)web框架:RequestHandler
2)web服务器:客户端,服务端(HTTPServer,AsyncHTTPClient)
3)异步网络库:IOLoop,IOStream
4)协程库:tornado.gen可以使异步代码用一种更加直接的方式去写,而不是回调链的方式

3.注意事项
Tornado的web框架,和服务器框架是基于WSGI的,但是同时使用效率会更高。

4.异步和非阻塞IO
1)为什么要用异步和非阻塞IO
传统的同步请求的web服务器,当有多个用户同时请求时,会为每个用户创建一个独立的线程,这是非常昂贵的。
Tornado使用单线程的事件循环来处理请求,也就是说任何时间只会有一个操作是激活状态的,这就要求应用程序的所有操作都应该是异步非阻塞的。

2)阻塞
一个函数在执行的过程中等待某个操作完成通知,才能继续执行后续的代码。
这个操作可能是网络IO,磁盘IO,或者一些耗时的计算等,此时函数执行会阻塞,长时间占用CPU时间。

3)异步
异步函数在执行完成之前返回,耗时操作会在后台执行或下次执行,应用程序可以去执行其他的操作。
耗时操作执行完毕后,会通过某种方式告诉应用程序,应用程序会接着执行未完成的函数,通知方式有以下几种。
回调
返回占位符(Future,Promise,Deferred),即未来会自动执行的对象
放入待处理队列
信号

4)同步,异步示例
同步请求:

from tornado.httpclient import HTTPClient

def sync_fetch():
    http_client = HTTPClient()
    response = http_client.fetch("http://www.baidu.com")
    print(response.body)
sync_fetch()

异步请求:
使用callback回调

from tornado.httpclient import AsyncHTTPClient, HTTPClient

def handle_response(response):
    print(response.body)

http_client = AsyncHTTPClient()
http_client.fetch("http://www.baidu.com", handle_response)
http_client.close()

使用占位符,也就是协程,将来执行对象

from tornado.httpclient import AsyncHTTPClient, HTTPClient
from tornado.concurrent import Future

http_client = AsyncHTTPClient()
my_future = Future()
fetch_future =http_client.fetch("http://www.baidu.com")
fetch_future.add_done_callback(
	lambda f:my_future.set_result(f.result())
)  

使用协程

from tornado.httpclient import AsyncHTTPClient, HTTPClient
from tornado import gen

@gen.coroutine
def fetch_coroutine():
    http_client = AsyncHTTPClient()
    response = yield http_client.fetch('http://www.baidu.com')
    raise gen.Return(response.body)

raise gen.Return(response.body):返回结果

5.协程
coroutines是Tornado推荐的异步代码编写方式,使用yield关键字挂起,恢复执行,来代替回调链。
协程的编写方式简单,并且减少了上下文切换,提升了效率。
1)python2中代码示例

from tornado.httpclient import AsyncHTTPClient, HTTPClient
from tornado import gen

@gen.coroutine
def fetch_coroutine():
    http_client = AsyncHTTPClient()
    response = yield http_client.fetch('http://www.baidu.com')
    raise gen.Return(response.body)

2)python3中代码示例

async def fetch_coroutine(url):
    http_client = AsyncHTTPClient()
    response = await http_client.fetch(url)
    return response.body

3)协程的原理
函数中包含yield关键字,那这个函数就是一个生成器,生成器是异步执行的。
生成器和函数的区别是,执行到yield关键字的地方返回,调用next()方法后,会继续接着yield表达式运行。
@gen.coroutine装饰器的作用是从生成器接收一个Future,等待(非阻塞)Future执行完成,发送Future结果到生成器,作为yield表达式的结果。

4)怎么执行协程
调用协程函数的函数必须也是个协程

@gen.coroutine
def divide(x, y):
    return x / y

def bad_call():
	# 错误
    divide(1, 0)

@gen.coroutine
def good_call():
    # 正确
    yield divide(1, 0)

协程的执行方式有两种:
IOLoop.spawn_callback
在下一次IOLoop循环时,运行协程函数.spawn_callback不需要调用者的上下文空间,适合独立的协程函数的执行。

IOLoop.current().spawn_callback(divide, 1, 0)

IOLoop.run_sync
开始一个IOLoop循环,执行给定的协程函数,结束IOLoop循环。
函数的返回结果必须是一个可以yieldable的对象或者None

tornado.ioloop.IOLoop.current().run_sync(lambda :divide(1, 2))

5)协程的几种模式
和callback交互
使用gen.Task包裹函数,gen.Task返回Future,可以yield

@gen.coroutine
def call_task():
    yield gen.Task(some_function, other_args)

协程函数中调用同步函数
使用ThreadPoolExecutor类,可以返回兼容协程的Futures

thread_pool = ThreadPoolExecutor(4)

@gen.coroutine
def call_blocking():
    yield thread_pool.submit(blocking_func, args)

等待所有Future对象执行完毕

@gen.coroutine
def parallel_fetch(url1, url2):
    resp1, resp2 = yield [http_client.fetch(url1),
                          http_client.fetch(url2)]

循环

import motor
db = motor.MotorClient().test

@gen.coroutine
def loop_example(collection):
    cursor = db.collection.find()
    while (yield cursor.fetch_next):
        doc = cursor.next_object()

posted on 2017-12-15 16:58  迪米特  阅读(646)  评论(0编辑  收藏  举报

导航