09 | Tornado源码分析:Future 对象

时间:2022-07-22
本文章向大家介绍09 | Tornado源码分析:Future 对象,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

今天我们来看一下 Future 这个对象。从字面意思来看有“未来,将来......”之意义。那它在Tornado 构建的体系中扮演者什么样的角色呢?我们先看一下它的源码:

以上是 Future 中比较核心的方法,为了我们能整体的把握这个类的内容明白其运行原理,我对这个类进行了整理,可以看一下我整理后对这个类中的核心代码的解释:

# -*- encoding: utf-8 -*-
# !/usr/bin/python
"""
@File    : future_learn.py
@Time    : 2020/07/25 15:40
@Author  : haishiniu
@Software: PyCharm
"""

class Future(object):
    def __init__(self):
        self._done = False # 异步操作是否执行完成
        self._result = None # 如果异步操作成功执行完成,则将结果保存到 self._result
        self._exc_info = None # 如果异步操作执行过程中出现异常,则将异常信息保存到self._exc_info
        self._callbacks = [] # 回调函数列表。在异步操作执行完成之后,会挨个调用这些回调函数

    def running(self):
        return not self._done

    def done(self):
        return self._done

    def result(self, timeout=None):
        # 如果异步操作成功执行,则返回它的结果
        if self._result is not None:
            return self._result
        # 如果异步操作执行失败,则重新抛出异常信息
        if self._exc_info is not None:
            try:
                raise_exc_info(self._exc_info)
            except Exception as ex :
                print(ex)
            finally:
                self = None

        # 如果异步操作尚未完成,则等待它执行结束,然后返回它的结果
        # 但是在 tornado 中没有实现阻塞的等待结果,
        # 如果异步操作没有完成,调用该方法会引发异常
        # 所以,最好是:
        # if future.done():
        #     result = future.result()
        #     ...
        self._check_done()
        return self._result

    def exception(self, timeout=None):
        # 如果异步操作抛出了异常,那么就返回异常对象
        if self._exc_info is not None:
            return self._exc_info[1]
        else:
            # 如果异步操作尚未完成,则抛出异常。
            # 如果异步操作成功执行,则返回None。
            self._check_done()
            return None

    def add_done_callback(self, fn):
        # 当异步操作已经执行完成时,立即调用回调函数
        if self._done:
            fn(self)
        # 否则,添加到回调函数列表。当异步操作执行完成时,会挨个调用这些回调函数
        else:
            self._callbacks.append(fn)

    def set_result(self, result):
        # 如果该 Future 对象所绑定的异步操作,成功执行了,在异步操作中
        # 应该调用 Future 对象的 set_result() 方法设置执行结果。
        # 该方法会将结果保存起来,并且将 Future 对象设置为完成,最后还会挨个调用回调函数
        self._result = result
        self._set_done()

    def set_exc_info(self, exc_info):
        # 将异常信息保存到 self._exc_info 属性
        self._exc_info = exc_info
        try:
            # 调用 _set_done() 将该Future对象标记位完成;并调用所有的回调函数
            self._set_done()
        except Exception as ex:
            print(ex)
        self._exc_info = exc_info

    def _check_done(self):
        # 因为在 tornado 的这个实现中,不支持阻塞等待异步操作的结果。
        # + 所以,当异步操作尚未完成时,会直接抛出异常。
        if not self._done:
            raise Exception("DummyFuture does not support blocking for results")

    def _set_done(self):
        self._done = True
        for cb in self._callbacks:
            try:
                # 执行回调
                cb(self)
            except Exception as ex:
                print(ex)
        # 回调完成后 回调队列设置为 None
        self._callbacks = None

在代码中我已经做了比较详尽的批注,大家可以结合代码和批注来理解这个类中的内容。 总结: 1. Future 对象是用来存储异步操作的结果的。 2. 在tornado中,Future 通常和 IOLoop.add_future()一起使用,或者由gen.coroutine 修饰的生成器函数yield它们。 3.本质上,Future就是一个"占位符"。 需要注意的是:Future是非线程安全的。

好的,本期我们就先分享到这里,若还有疑问可以给我留言进行进一步的交流,谢谢。