美文网首页
tornado协程调度

tornado协程调度

作者: EamonYi | 来源:发表于2019-10-04 12:27 被阅读0次

环境配置

win10
pycharm64 5.0.3
python 3.6.7
tornado 5.1.1

示例代码

参考自tornado协程(coroutine)原理

from tornado.gen import coroutine

@coroutine
def asyn_sum(a, b):
    print("begin calculate:sum %d+%d"%(a,b))
    result = yield simple_plus(a, b)

    print("after yielded")
    print("the %d+%d=%d" % (a, b, result))

@coroutine
def simple_plus(a, b):
    return a+b

def main():
    asyn_sum(2, 3)
    # tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()

执行过程

@coroutine装饰的方法实际执行的函数是gen.py中的_make_coroutine_wrapper装饰器返回的方法wrapper(暂且称之为asyn_sum_wrapper),且wrapper中的functypes.coroutine处理后的方法。

asyn_sum执行过程

asyn_sum_wrapper方法的执行结果result = func(*args, **kwargs)实际是一个GeneratorType类型的对象,实际的执行是在yielded = next(result)中。执行到result = yield simple_plus(a, b)时,进入simple_plus被装饰后的方法wrapper中(暂且称之为simple_plus_wrapper)。simple_plus_wrapper返回一个Future对象,其result属性为5,即其实际返回值,随后跳转到runner = Runner(result, future, yielded)

Runner的实例化有一段执行代码

if self.handle_yield(first_yielded):
    gen = result_future = first_yielded = None
    self.run()

self.handle_yield会将self.future置为first_yielded,然后各个指向这个future的变量置空;在self.run()self.future会赋值给局部变量future,然后被置空;在执行value = future.result()后该局部变量也被置空。future最终只有外层的Runner初始化时候的引用,Runner返回后yielded=None,等待释放。

获得了simple_plus返回结果后,gen.py使用yielded = self.gen.send(value)回归到asyn_sum的yield,并将返回值写入result,此时self.run()被挂起,等asyn_sum执行完后恢复执行。

asyn_sum执行完后,会跳转到异常捕获逻辑except (StopIteration, Return) as e:e就是asyn_sum的返回值,后续被future_set_result_unless_cancelled(self.result_future, _value_from_stopiteration(e))将值写回到result_future中,即asyn_sum_wrapper调用初期实例化的future对象。

simple_plus执行过程

simple_plus同样也是在simple_plus_wrapperresult = func(*args, **kwargs)处执行,不同的是,simple_plus方法体不包含yield,所以在types.coroutine.wrapped返回的不再是GeneratorType类型的对象,而是simple_plus方法的实际执行结果5,然后在装饰器内会包装上Future返回给上层调用者。

future

@coroutine装饰器的wrapper中,第一步就是定义一个future对象,在asyn_sum_wrapper执行过程中,由于内部调用了yield,所以在它的future被使用前,又进入了simple_plus_wrapper。由于后者的result是非GeneratorType类型,所以跳转到了future_set_result_unless_cancelled(future, result)

从gen.py中可以追溯Future的定义位置,根据实际单步定位,Future定义在_asyncio.py中,因为future的方法无法跳转。

# gen.py
from tornado.concurrent import (Future, is_future, chain_future, future_set_exc_info,
                                future_add_done_callback, future_set_result_unless_cancelled)
# concurrent.py
if asyncio is not None:
    Future = asyncio.Future  # noqa

if futures is None:
    FUTURES = Future  # type: typing.Union[type, typing.Tuple[type, ...]]
else:
    FUTURES = (futures.Future, Future)

协程切换

参考自关于协程的 send(None)
为方便对yielded = self.gen.send(value)的理解,此处保留代码示例。

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

未了解部分

Runner中的self._deactivate_stack_context()future_set_exc_info(self.result_future, sys.exc_info())

小结

tornado中每一个被coroutine装饰的方法都会对应一个future,根据调用的深度,future的嵌套深度逐渐增加,直到某一个future set_result(result = func(*args, **kwargs)返回结果为非生成器类型),然后进行后续future的嵌套处理。

对yield AsyncHTTPClient的调用,yielded = next(result)会获取到fetch返回的future对象,与调用者及其future对象一并生成一个Runner对象,供IOloop异步回调,runner中yielded = self.gen.send(value)会触发协程从断点继续执行。

相关文章

  • tornado协程调度

    环境配置 win10pycharm64 5.0.3python 3.6.7tornado 5.1.1 示例代码 参...

  • 如何分析tornado源码和调试跟踪

    “协程”“异步”“一个tornado可以并发处理几万长连接”“tornado和gevent是两种不同的协程方式” ...

  • python tornado TCPserver异步协程实例

    项目所用知识点 tornado socket tcpserver 协程 异步 tornado tcpserver源...

  • [Android] 深入理解Kotlin协程

    Kotlin协程 协程由程序自己创建和调度,不需要操作系统调度,所以协程比线程更加轻量。相比于线程的切换,协程切换...

  • 协程

    协程与线程 线程的调度是由操作系统负责,协程调度是程序自行负责 与线程相比,协程减少了无谓的操作系统切换 协程实际...

  • [libco] 协程调度

    libco 通过 co_resume 和 co_yield 交替调度协程。 文章来源:[libco] 协程调度[h...

  • Tornado入门(三)【协程】

    协程 在Tornado中,协程是推荐使用的异步方式。协程使用yield关键字暂停或者恢复执行,而不是回调链的方式。...

  • 十分钟看懂:Java并发——协程

    协程 协程可以理解为一种轻量级的线程 从操作系统的角度来看,线程是在内核态中调度的,而协程是在用户态调度的,协程的...

  • base learn

    多线程,多进程,协程 huey,celery,redis,memcached tornado,middleware...

  • (2018-05-30.Python从Zero到One)8、(T

    7.4 练习 请解释清同步、异步、yield、协程几个概念和Tornado实现异步的原理。 练习使用Tornado...

网友评论

      本文标题:tornado协程调度

      本文链接:https://www.haomeiwen.com/subject/fofeaqtx.html