目录


概述[TOC]

源代码在:http://www.tornadoweb.org/en/stable/_modules/tornado/concurrent.html#Future

Future用来囊括异步操作的结果。在tornado中,Future通常和IOLoop.add_future()一起使用,或者由gen.coroutine修饰的生成器函数yield它们。
当调用一个异步操作的时候,它会立即返回一个Future对象。然后,调用方在返回的Future对象上,设置回调函数。异步操作会将自己注册到IOLoop事件循环上,每次事件循环,都会“向前推进”异步操作,当异步操作完成时,它会将结果或异常信息,填充到Future对象中,并且会使用该Future对象作为参数 调用 该Future对象上设置的回调函数。所以,本质上,Future就是一个“占位符”。
需要注意的是:Future是非线程安全的。


主要方法[TOC]

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):
        """Returns True if this operation is currently running."""
        return not self._done

    def done(self):
        """Returns True if the future has finished running."""
        return self._done

    def result(self, timeout=None):
        """If the operation succeeded, return its result.  If it failed,
        re-raise its exception.

        This method takes a ``timeout`` argument for compatibility with
        `concurrent.futures.Future` but it is an error to call it
        before the `Future` is done, so the ``timeout`` is never used.
        """
        # 如果异步操作成功执行,则返回它的结果
        if self._result is not None:
            return self._result
        # 如果异步操作执行失败,则重新抛出异常信息
        if self._exc_info is not None:
            try:
                raise_exc_info(self._exc_info)
            finally:
                self = None

        # 如果异步操作尚未完成,则等待它执行结束,然后返回它的结果
        # + !!!但是在tornado中没有实现阻塞的等待结果,
        # + + 如果异步操作没有完成,调用该方法会引发异常!!!
        # + 因此,最好是:
# if future.done():
#     result = future.result()
#     ...
self._check_done() return self._result def exception(self, timeout=None): """If the operation raised an exception, return the `Exception` object. Otherwise returns None. This method takes a ``timeout`` argument for compatibility with `concurrent.futures.Future` but it is an error to call it before the `Future` is done, so the ``timeout`` is never used. """ # 如果异步操作抛出了异常,那么就返回异常对象 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): """Attaches the given callback to the `Future`. It will be invoked with the `Future` as its argument when the Future has finished running and its result is available. In Tornado consider using `.IOLoop.add_future` instead of calling `add_done_callback` directly. """ # 当异步操作已经执行完成时,立即调用回调函数 if self._done: fn(self) # 否则,添加到回调函数列表。当异步操作执行完成时,会挨个调用这些回调函数 else: self._callbacks.append(fn) def set_result(self, result): """Sets the result of a ``Future``. It is undefined to call any of the ``set`` methods more than once on the same object. """ # 如果该Future对象所绑定的异步操作,成功执行了,在异步操作中 # 应该调用Future对象的set_result()方法设置执行结果。 # 该方法会将结果保存起来,并且将Future对象设置为完成, # + 最后,还会挨个调用回调函数 self._result = result self._set_done() def set_exc_info(self, exc_info): """Sets the exception information of a ``Future.`` Preserves tracebacks on Python 2. .. versionadded:: 4.0 """ # 将异常信息保存到self._exc_info属性 self._exc_info = exc_info try: # 调用_set_done()将该Future对象标记位完成;并调用所有的回调函数 self._set_done() finally: ... 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: app_log.exception('Exception in callback %r for %r', cb, self) self._callbacks = None