zoukankan      html  css  js  c++  java
  • tornado用户指引(四)------tornado协程使用和原理(三)

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/happyAnger6/article/details/51291221
    几种常用的协程方式:

    1.回调函数

    如果你要执行的异步代码是基于回调函数而不是基于Future的,你可以将异步代码通过Task装饰起来。这样Task装饰器会为你添加callback并返回一个Future,这样你就可以用yield来执行异步代码。

    @gen.coroutine
    def call_task():
    # Note that there are no parens on some_function.
    # This will be translated by Task into
    # some_function(other_args, callback=callback)
      yield gen.Task(some_function, other_args)
    在some_function里,你可以执行基于回调函数的异步代码。gen.Task会为你设置好一个callback并通过callback参数传递给some_function,你在some_function内部将callback传递给异步代码所需的callback即可。


    2.调用阻塞函数

    调用阻塞函数最简单的办法是通过使用ThreadPoolExecutor,它会返回一个Future.

    thread_pool = ThreadPoolExecutor(4)

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

    3.并行

    coroutine装饰器能够识别Future的列表或字典,能够并行执行它们并等待全部完成。

    @gen.coroutine
    def parallel_fetch(url1, url2):
      resp1, resp2 = yield [http_client.fetch(url1),
      http_client.fetch(url2)]

    @gen.coroutine
    def parallel_fetch_many(urls):
      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):
      responses = yield {url: http_client.fetch(url) for url in urls}
      # responses is a dict {url: HTTPResponse}

    4.在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()

    5.循环

    由于在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()

    6.在后台执行

    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 # 此时再等待定时器超时.

    ---------------------
    作者:self-motivation
    来源:CSDN
    原文:https://blog.csdn.net/happyAnger6/article/details/51291221
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    2016.5.11_经典试题-回文算法【ABAP】
    shell基础知识
    python笔记2
    python笔记1
    vmware rdm
    网页中图片显示方向与实际图片方向不一致
    vue 弹性布局 实现长图垂直居上,短图垂直居中
    IE10 解决input file 同一文件不触发onchange事件
    04. pt-deadlock-logger
    03. pt-config-diff
  • 原文地址:https://www.cnblogs.com/b02330224/p/10213996.html
Copyright © 2011-2022 走看看