tornado 第一篇

 一:异步和非阻塞IOhtml

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

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

  1,阻塞服务器

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

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

  2,异步异步

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

    1,回调函数ide

    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

相关文章
相关标签/搜索