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()
    
  • 相关阅读:
    Atitit.播放系统规划新版本 v4 q18 and 最近版本回顾
    Atitit.播放系统规划新版本 v4 q18 and 最近版本回顾
    atitit.极光消息推送服务器端开发实现推送  jpush v3. 总结o7p
    atitit.极光消息推送服务器端开发实现推送  jpush v3. 总结o7p
    Atitit.文件搜索工具 attilax 总结
    Atitit.文件搜索工具 attilax 总结
    Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package
    Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package
    Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结
    Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/8043954.html
Copyright © 2011-2022 走看看