资讯专栏INFORMATION COLUMN

再次阅读 Tornado 中的 coroutine 代码

rottengeek / 2595人阅读

摘要:一年多前的文章这次重新读,再加上一些中给我的知识,有了更深的理解。

一年多前的文章 http://segmentfault.com/a/1190000000426460 这次重新读,再加上一些 js 中 co给我的知识,有了更深的理解。

Front Knowledge

yield and generator will be the front knowledge of this article. And you should also have some sense of epoll/kqueue and callback style. Let"s enjoy the source code of the implement of coroutine.

Python Tornado

A simple async fetch function used by a coroutine in Python, exception handle removed

def fetch(self, request):
    future = TracebackFuture() # TracebackFuture == Future
    def handle_response(response):
        future.set_result(response)
    self.fetch_impl(request, handle_response) # This is a async function
    return future

def fetch_impl(self, request, callback):
    pass

future -- an instance of Future -- is an object that used to collect and send result to generator.

A coroutine that uses above fetch

@gen.coroutine
def request(self, uri):
    response = yield http.fetch(uri)

And we all know @gen.coroutine is a syntax sugar of

request = gen.coroutine(request)

coroutine wrapper function, also exception handle removed

def _make_coroutine_wrapper(func, replace_callback):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
        try:
            result = func(*args, **kwargs) # result is a generator if the function is a generator function
        except (Return, StopIteration) as e:
            result = getattr(e, "value", None)
        else:
            if isinstance(result, types.GeneratorType): # if the function is a generator function
                try:
                    yielded = next(result) # generator.next() will run the code above and right hand of the generator, for our example request here, http.fetch(uri) will run and return yielded(a instance of Future).
                except (StopIteration, Return) as e:
                    future.set_result(getattr(e, "value", None))
                else:
                    Runner(gen=result, result_future=future, first_yielded=yielded) # Runner is like the co lib in Js written by TJ, Runner use a While True rather than recursive, because recursive is slower in Python.
                return future
            else: # or the function is jsut a normal function
              pass 
        future.set_result(result)
        return future
    return wrapper

With the Tornado usage we can learn that the function after yield can be either a coroutine or a normal function.
Both of them returns a Future. You can write return Future by yourself or use @coroutine. But make sure your normal function is an async function.

Runner.run function, exception handle removed

def __init__(self, gen, result_future, first_yielded): # init of Runner
    ... # some attrs bind
    self.future = first_yielded # removed some complex logic, just show the basic logic of running the `request` generator.
    self.io_loop.add_future(
                self.future, lambda f: self.run()) # io_loop is a epoll based loop, the second function is a callback function when future is finished.

def run(self):
"""Starts or resumes the generator, running until it reaches a
yield point that is not ready.
"""
    while True:
        if not future.done():
            return
        try:
            value = future.result()
            yielded = self.gen.send(value)
        except (StopIteration, Return) as e:
            self.finished = True
            return
        except Exception:
            self.finished = True
            return
        if not self.handle_yield(yielded):
            return

Runner is like the co lib in Js written by TJ, Runner use a While True rather than recursive, because recursive is slower in Python. Both of them do the same thing, that is executing the generator unitl it"s done.

First of all, Runner add the future, or we can say the async function fetch to io_loop. If fetch is finish, itself will invoke the callback function handle_response to set data to future. And the io_loop will invoke another callback function lambda f: self.run() to run the function run to get the result from future by value = future.result() and send to the generator by yield = gen.send(value) and start the next block of the generator function if exists until the whole function is stoped and return a StopIteration.

So let us figure out the effect of each object:

generator function: a function with yield statement

generator: invoke a generator function will return a generator

coroutine: a wrapper function to wrapper a generator function. It will create a runner to run the generator.

Future: used to collect and get result, it"s a result container.

Runner: it will register the future to io_loop and send result back to generator, and repeats unitl generator is done.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37715.html

相关文章

  • tornado 源码阅读-初步认识

    摘要:序言最近闲暇无事阅读了一下的源码对整体的结构有了初步认识与大家分享不知道为什么右边的目录一直出不来非常不舒服不如移步到吧是的核心模块也是个调度模块各种异步事件都是由他调度的所以必须弄清他的执行逻辑源码分析而的核心部分则是这个循环内部的逻辑贴 序言 最近闲暇无事,阅读了一下tornado的源码,对整体的结构有了初步认识,与大家分享 不知道为什么右边的目录一直出不来,非常不舒服. 不如移...

    2450184176 评论0 收藏0
  • Tornado Demo 之 chatdemo 不完全解读

    摘要:清楚了以上流程,我们直接来看函数主要用作初始化应用监听端口以及启动。其中就是保存聊天室所有聊天消息的结构。关于的解读我会放到阅读源码时讲。然后把消息加到缓存里,如果缓存大于限制则取最新的条消息。 tornado 源码自带了丰富的 demo ,这篇文章主要分析 demo 中的聊天室应用: chatdemo 首先看 chatdemo 的目录结构: ├── chatdemo.py ├── ...

    TesterHome 评论0 收藏0
  • 谈谈项目的重构与测试

    这篇文章摘自我的博客, 欢迎大家没事去逛逛~ 背景 这几个月我开发了公司里的一个restful webservice,起初技术选型的时候是采用了flask框架。虽然flask是一个同步的框架,但是可以配合gevent或者其它方式运行在异步的容器中(测试链接),效果看上去也还可以,因此就采用了这种方式。 后面阅读了tornado的源码,也去了解了各种协程框架以及运行的原理。总感觉flask的这种同步...

    Lavender 评论0 收藏0
  • 谈谈项目的重构与测试

    这篇文章摘自我的博客, 欢迎大家没事去逛逛~ 背景 这几个月我开发了公司里的一个restful webservice,起初技术选型的时候是采用了flask框架。虽然flask是一个同步的框架,但是可以配合gevent或者其它方式运行在异步的容器中(测试链接),效果看上去也还可以,因此就采用了这种方式。 后面阅读了tornado的源码,也去了解了各种协程框架以及运行的原理。总感觉flask的这种同步...

    wuaiqiu 评论0 收藏0
  • Python:Tornado 第一章:异步及协程基础:第三节:协程

    摘要:上一篇文章第一章异步及协程基础第二节关键字下一篇文章第二章实战演练开发网站第一节网站结构使用协程可以开发出类似同步代码的异步行为。协程函数可以通过以下三张方式调用在本身是协程的函数内通过关键字调用。 上一篇文章:Python:Tornado 第一章:异步及协程基础:第二节:Python关键字yield下一篇文章:Python:Tornado 第二章:实战演练:开发Tornado网站:第...

    charles_paul 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<