tornado 源码之 coroutine 分析
tornado 源码之 coroutine 分析tornado 的协程原理分析 版本:4.3.0为支持异步,tornado 实现了一个协程库。tornado 实现的协程框架有下面几个特点:支持 python 2.7,没有使用 yield from特性,纯粹使用 yield 实现使用抛出异常的方式从协程返回值采用 Future 类代理协程(保存协程的执行结果,当携程执行结束时,调用注册的回调函数)使用 IOLoop 事件循环,当事件发生时在循环中调用注册的回调,驱动协程向前执行由此可见,这是 python 协程的一个经典的实现。本文将实现一个类似 tornado 实现的基础协程框架,并阐述相应的原理。外部库使用 time 来实现定时器回调的时间计算。 bisect 的 insort 方法维护一个时间有限的定时器队列。 functools 的 partial 方法绑定函数部分参数。 使用 backports_abc 导入 Generator 来判断函数是否是生成器。import timeimport bisectimport functoolsfrom backports_abc import Generator as GeneratorTypeFuture是一个穿梭于协程和调度器之间的信使。 提供了回调函数注册(当异步事件完成后,调用注册的回调)、中间结果保存、结束结果返回等功能add_done_callback 注册回调函数,当 Future 被解决时,改回调函数被调用。 set_result 设置最终的状态,并且调用已注册的回调函数协程中的每一个 yield 对应一个协程,相应的对应一个 Future 对象,譬如:@coroutinedef routine_main(): yield routine_simple() yield sleep(1)这里的 routine_simple() 和 sleep(1) 分别对应一个协程,同时有一个 Future 对应。class Future(object): def init(self): self._done = False self._callbacks = [] self._result = None def _set_done(self): self._done = True for cb in self._callbacks: cb(self) self._callbacks = None def done(self): return self._done def add_done_callback(self, fn): if self._done: fn(self) else: self._callbacks.append(fn) def set_result(self, result): self._result = result self._set_done() def result(self): return self._resultIOLoop这里的 IOLoop 去掉了 tornado 源代码中 IO 相关部分,只保留了基本需要的功能,如果命名为 CoroutineLoop 更贴切。这里的 IOLoop 提供基本的回调功能。它是一个线程循环,在循环中完成两件事:检测有没有注册的回调并执行检测有没有到期的定时器回调并执行程序中注册的回调事件,最终都会在此处执行。可以认为,协程程序本身、协程的驱动程序 都会在此处执行。协程本身使用 wrapper 包装,并最后注册到 IOLoop 的事件回调,所以它的从预激到结束的代码全部在 IOLoop 回调中执行。而协程预激后,会把 Runner.run() 函数注册到 IOLoop 的事件回调,以驱动协程向前运行。理解这一点对于理解协程的运行原理至关重要。这就是单线程异步的基本原理。因为都在一个线程循环中执行,我们可以不用处理多线程需要面对的各种繁琐的事情。coroutine协程返回值sleepRunner因为没有使用 yield from,协程无法直接返回值,所以使用抛出异常的方式返回。copyrightauthor:bigfish copyright: 许可协议 知识共享署名-非商业性使用 4.0 国际许可协议 ...