zoukankan      html  css  js  c++  java
  • 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()
    
  • 相关阅读:
    20121025
    活到老学到老
    VS2012 正式版BUG太多
    JSP页面basePath路径问题
    这样的日子
    正确用JQ的AJAX加载XML并解析
    JSP中的5中转发方式
    C#编码规范
    jsp判断用户是否在线
    beging
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/8043954.html
Copyright © 2011-2022 走看看