tornado用户指引系列:协程异步

#1.同步tornado
from tornado.httpclient import HTTPClient
def synchronous_fetch(url):
    http_client = HTTPClient()
    response = http_client.fetch(url)
    return response.body

#2.1回调函数实现的异步
from tornado.httpclient import AsyncHTTPClient
def asynchronous_fetch(url, callback):
    http_client = AsyncHTTPClient()
    def handle_response(response):
        callback(response)
    http_client.fetch(url, callback=handle_response)

#2.2回调函数实现的异步
from tornado.concurrent import Future
def asynchronous_fetch_future(url):
    http_client = AsyncHTTPClient()
    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

#3.协程实现的异步
from tornado import gen
@gen.coroutine
def fetch_coroutine(url):
    http_client = AsyncHTTPClient()
    response = yield http_client.fetch(url)
    return response.body
    # python2.7,python3.3不支持将生成器函数作为返回值
    # 为了克服这个,Tornado coroutines抛出一个特殊种类的异常,称为Return.
    # raise gen.Return(response.body)

 

tornado官方建议,使用协程实现的异步。

tornado协程实现的异步,还可以有不同的调用方式,具体分为:

# 1.调用阻塞函数
# 调用阻塞函数最简单的办法是通过使用线程池ThreadPoolExecutor,它会返回一个Future.
#线程池使用方式一:thread_pool.submit
from concurrent.futures import ThreadPoolExecutor
thread_pool = ThreadPoolExecutor(4)
@gen.coroutine
def call_blocking():
    yield thread_pool.submit(blocking_func, args)

#线程池使用方式一: run_on_executor装饰器
from tornado.concurrent import run_on_executor
class IndexHandler(BaseHandler):
    executor = ThreadPoolExecutor(4)
    @gen.coroutine
    def get(self):
        res = yield self.back_handle()
        self.set_header("Content-Type", "application/json")
        self.finish(res)
    @gen.coroutine
    def post(self, *args, **kwargs):
        res = yield self.back_handle()
        self.set_header("Content-Type", "application/json")
        self.finish(res)
    @run_on_executor
    def back_handle(self):
        res = "blocking-func something........."
        return res
import tornado.web
class BaseHandler(tornado.web.RequestHandler):
    def data_received(self, chunk):
        u"""不知道干嘛的,不实现这个会有异常提醒。先放着"""
        pass

    def __init__(self, *argc, **argkw):
        super(BaseHandler, self).__init__(*argc, **argkw)

    def get_connect(self, conn_name):
        return self.application.get_connect(conn_name)

    def set_default_header(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        self.set_header('Access-Control-Allow-Headers', 'x-requested-with')
        self.set_header('Access-Control-Allow-Methods', 'POST, GET')

#2.并行
# coroutine装饰器能够识别Future的列表或字典,能够并行执行它们并等待全部完成。
@gen.coroutine
def parallel_fetch(url1, url2):
    http_client = AsyncHTTPClient()
    resp1, resp2 = yield [http_client.fetch(url1),
                          http_client.fetch(url2)]
@gen.coroutine
def parallel_fetch_many(urls):
    http_client = AsyncHTTPClient()
    responses = yield [http_client.fetch(url) for url in urls]
    # responses is a list of HTTPResponses in the same order
@gen.coroutine
def parallel_fetch_dict(urls):
    http_client = AsyncHTTPClient()
    responses = yield {url: http_client.fetch(url)
                        for url in urls}
    # responses is a dict {url: HTTPResponse}

#3.在yield前插入其它代码
# 有时候,你需要暂存一个Future而不立即yield它。在此之前可以执行一些其它操作。
@gen.coroutine
def get(self):
    fetch_future = self.fetch_next_chunk()
    while True:
        chunk = yield fetch_future #这里对取到的Future执行yield
        if chunk is None: break
        self.write(chunk)
        fetch_future = self.fetch_next_chunk() #先得到Future而不立刻对其yield
        yield self.flush()

#4.循环
# 由于在python没有办法对for和while循环的每次迭代yield并同时获取结果,所以在循环中使用协程需要一些技巧。
# 你需要将循环条件和访问结果分开进行,下面的例子演示了这一点:
# motor是一个mongodb的python api,它的实现也是基于协程方式,可以十分方便地在tornado中使用它。
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()

#5.在后台定期地执行
# PeriodicCallback(用于定期地执行一个函数)在协程中并不十分常用。
# 你可以在协程中使用一个循环,在循环中使用tornado.gen.sleep达到同样的效果。
@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)
# 有时候,你可能需要执行一个更复杂的循环逻辑。比如,上面的例子中循环体每60+N s运行一次,N是do_something()函数执行的时间.如果你想精确控制每次循环执行时间为60s,你可以像下面这样做:
@gen.coroutine
def minute_loop2():
    while True:
        nxt = gen.sleep(60)   # 启动一个定时器并不yield它.
        yield do_something()  # 在执行定时器的同时执行函数
        yield nxt             # 此时再等待定时器超时.

 

 

 

tornado(二):表单和模板

在tornado框架中,模板可以以{% if、for、函数、表达式、赋值 %}使用python语法!!! 在其它python框架中,是不可以的,使用的html语法。

 

Tornado用户指引(一)-----------异步和非阻塞I/O

tornado用户指引(二)------------tornado协程实现原理和使用(一)

https://www.cnblogs.com/b02330224/p/10200902.html

tornado用户指引(三)------tornado协程使用和原理(二)

https://blog.csdn.net/happyAnger6/article/details/51277407

tornado用户指引(四)------tornado协程使用和原理(三)

https://blog.csdn.net/happyAnger6/article/details/51291221

tornado用户指引(五)------- 一个并发的web爬虫:

https://blog.csdn.net/happyAnger6/article/details/51292536

tornado用户指引(六)------Tornado web应用程序结构(一)之Applicaton对象

https://blog.csdn.net/happyAnger6/article/details/51296018

 

posted on 2017-08-07 20:58  myworldworld  阅读(210)  评论(0)    收藏  举报

导航