zoukankan      html  css  js  c++  java
  • tornado 第一篇

     一:异步和非阻塞IO

      实时的web特性通常需要每个用户一个大部分时间,在传统的同步web服务器中,这意味着需要给每个用户分配一个专用的线程,这样的开销是十分巨大

      tornado使用啦一种单线程事件循环的方式,这意味着所有的应用代码都应该是异步和非阻塞的,因为在同一时刻只有一个操作是有效的

      1,阻塞

        一个函数在等到返回值等都是阻塞的,

        一个函数可以在某些方面阻塞而在其他方面不阻塞,举例说明。tornado,httpclient在默认设置下讲阻塞与DNS解析,但是在其他网络请求时不会阻塞(为了减轻这种影响,可以用ThreadeResolver 或通过正确配置libcurl使用tornado.curl_htpclient),在Tornado的上下文中我们通常讨论网络I/O上下文阻塞,虽然各种阻塞已经被最小化啦

      2,异步

        一个异步函数在在它结束前就已经返回啦,而且通常会在程序中触发一些动作然后在后头执行一些任务,这里有几种类型的异步接口

        1,回调函数

        2,返回一个占位符(Future,Promise,Deferred)

        3,传送一个队列

        4,回调注册

        一个简单的同步异步函数

        

    from tornado.httpclient import HTTPClient
    from tornado.concurrent import Future
    def synchronous_fetch(url):
        http_client = HTTPClient()
        def handle_response(response):
            callback(response.body)
        http_client.fetch(url,callbace=handle_response)

        在一次通过Future替代回调函数

        

    def async_fetch_future(url):
        http_client=HTTPClient()
        my_future=Future()
        fetch_future=http_client.fetch(url)
        fetch_future.add_done_callback(
            lambda f:my_future.set_result(f.result)
        )
    
        return my_future

        原始的Future是很复杂的,但是Futures是tornado中推荐使用的一种做法,因为他有两个优势

        错误处理是通过Future.result 函数可以简单抛出一个异常,还有就是携程兼容比较好

       

    rom tornado import gen
    
    @gen.coroutine
    def fetch_coroutine(url):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch(url)
        raise gen.Return(response.body)

        语句 raise gen.Return(response.body) 在 Python 2 中是人为设定的, 因为生成器不允许又返回值. 为了克服这个问题, Tornado 协程抛出了一个叫做 Return 的特殊异常. 协程将会像返回一个值一样处理这个异常.在 Python 3.3+ 中, return response.body 将会达到同样的效果.

    二:协程

      tornado中推荐协程来编写异步代码,协程使用python中关键件yield替换链式回调实现挂起和继续协程的执行(像在gevent中使用轻量级线程合作的方法有时也称作为协程,但是在Tornado中所有的协程使用异步函数来实现明确的上下文切换)

      看下协程的代码

    from tornado import gen
    from tornado import HTTPClient
    def fetch_coroutie(url):
        http_client=AsyncHTTPClient() 
      respone
    =yield http_client.fetch(url)

      # raise gen.Return(respone.body)
      
      return respone.body

       python3.5 async和awiat 

       python3.5 引入啦async和await 从tornado4.3开始,在协程基础上你可以使用这个来代替yield,简单的通过使用async def foo()来替代 @gen.coroutine 装饰器,用await来代替yield,可以看下下面的例子

      

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

        一个含有yield的函数时是一个生成器,所有的生成器都是异步的,调用它时将会返回一个对象而不是将函数运行完成,@gen.coroutine修饰器通过yeild表达式通过产生一个Future对象和生成器进行通信

        可以看下一个协程装饰器内部循环的简单版本

        

    def run(self):
        future=self.gen.send(self.next)
        
        def callback(f):
            self.next=f.result()
            self.run()
        future.add_done_callback(callback)

        

    有时你并不想等待一个协程的返回值. 在这种情况下我们推荐你使用 IOLoop.spawn_callback, 这意味着 IOLoop 负责调用. 如果它失败了, IOLoop 会在日志中记录调用栈:  同时注意spawn_callback调用的函数,也必须是协程函数

    # The IOLoop will catch the exception and print a stack trace in
    # the logs. Note that this doesn't look like a normal call, since
    # we pass the function object to be called by the IOLoop.
    IOLoop.current().spawn_callback(divide, 1, 0)


      协程模式
       1,结合callbacks
          
    为了使用回调来代替Future与异步代码进行交互,将这个调用装在task中,这将会在你生成的Future对象中添加一个回调参数
          
    @gen.coroutine
    def call_task():
    
        yield gen.Task(some_function, other_args)
        #把yeild换成gen_Task  

         2,调用阻塞函数

          在协程中调用阻塞函数的最简单方法是使用ThreadPoolExecutor  这将返回与协程兼容的Futures

          

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

          3,并行

            协程装饰器识别列表或者字典中的Futures,并且并行等待这些Fuures

        

    @gen.coroutine
    def parallel_fetch(url1,url2):
        resp1,resp2 = yield [http_client.fetch(url1),
                             http_client.fetch(url2)]
    
    
    
    @gen.coroutine
    def parallel_fetch_dict(urls):
        responses = yield {url: http_client.fetch(url)
                            for url in urls}

          4,交叉存取技术(项目一般用到比较多)

            有时保存一个Future比立刻yield它更有用,你可以等待它之前执行其他操作

            

    def get(self):
        fetch_future = self.fetch_next_chunk()
        while True:
            chunk = yield fetch_future
            if chunk is None:break
            self.write(chunk)
            fetch_future= self.fetch_next_chunk()
            yield self.flush()

          5,循环

            因为python无法使用forwhile循环yield迭代器,并且捕获yield的返回结果,相反,你需要将循环和访问结果区分开来,

          

    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()

          6,在后台运行

    @gen.coroutine
    def minute_loop():
        while True:
            yield do_something()
            yield gen.sleep(60)
    
    # Coroutines that loop forever are generally started with
    # spawn_callback().
    IOLoop.current().spawn_callback(minute_loop)

    更过内容可以参考:http://tornado-zh-cn.readthedocs.io/zh_CN/latest/guide/coroutines.html#python-3-5-async-await

            

     

        

      

  • 相关阅读:
    Feign调用文件上传服务接口样例
    Feign调用文件下载服务接口样例
    使用Spring Security的Basic Auth认证后Postman的POST请求不成功的可能原因
    Spring Boot应用的Controller返回的集合类数据是XML格式的可能原因
    Eureka Server增加Spring Security后的服务端和客户端配置
    Spring Data支持的关键字
    JPA(Hibernate)代理类的hibernateLazyInitializer属性系列化异常
    Spring Boot中fastjson的@JSONField(format = "yyyy-MM-dd HH:mm:ss")失效可能原因
    使用Java代码配置MyBatis Generator
    CentOS8.1中搭建Nexus3服务器
  • 原文地址:https://www.cnblogs.com/1204guo/p/8533421.html
Copyright © 2011-2022 走看看