# 期程

期程 对象用来链接 底层回调式代码 和高层异步/等待式代码。

## 期程函数

`asyncio.``isfuture`(obj)

  如果 obj 为下面任意对象，返回 `True`：

  - an instance of `asyncio.Future`,

  - an instance of `asyncio.Task`,

  - 带有 `_asyncio_future_blocking` 属性的类似期程的对象。

  3.5 新版功能.

`asyncio.``ensure_future`(obj, *, loop=None)

  返回：

  - obj 参数会是保持原样，如果 obj 是 `Future`、 `Task` 或 类似期程的对象( `isfuture()` 用于测试)

  - 封装着 obj 的 `Task` 对象 ，如果 obj 是一个协程( `iscoroutine()` 用于测试)

  - 等待 obj 的 `Task` 对象，如果 obj 是一个可等待对象( `inspect.isawaitable()` 用于测试)

  如果 obj 不是上述对象会引发一个 `TypeError` 异常。

  重要

  查看 `create_task()` 函数，它是创建新任务的首选途径。

  在 3.5.1 版更改: 这个函数接受任意 awaitable 对象。

`asyncio.``wrap_future`(future, *, loop=None)

  将一个 `concurrent.futures.Future` 对象封装到 `asyncio.Future` 对象中。

## 期程对象

class `asyncio.``Future`(*, loop=None)

  一个期程代表一个异步运算的最终结果。线程不安全。

  期程是一个 awaitable 对象。协程可以等待期程对象直到它们有结果或异常集合或被取消。

  通常期程用于支持底层回调式代码(例如在协议实现中使用asyncio transports) 与高层异步/等待式代码交互。

  经验告诉我们永远不要面向用户的接口暴露期程对象，同时建议使用 `loop.create_future()` 来创建期对象。这种方法可以让期程对象使用其它的事件循环实现，它可以注入自己的优化实现。

  在 3.7 版更改: 加入对 `contextvars` 模块的支持。

  `result`()

    返回期程结果。

    如果期程状态为 完成 ，并由 `set_result()` 方法设置一个结果，则返回这个结果。

    如果期程状态为 完成 ，并由 `set_exception()` 方法设置一个异常，那么这个方法会引发异常。

    如果期程已 取消，方法会引发一个 `CancelledError` 异常。

    如果期程的结果还不可用，此方法会引发一个 `InvalidStateError` 异常。

  `set_result`(result)

    将期程标记为 完成 并设置结果。

    如果期程已经 完成 则引发一个 `InvalidStateError` 错误。

  `set_exception`(exception)

    将期程标记为 完成 并设置一个异常。

    如果期程已经 完成 则引发一个 `InvalidStateError` 错误。

  `done`()

    如果期程为已 完成 返回 `True` 。

    如果期程为 取消 或调用 `set_result()` 设置了结果或调用 `set_exception()` 设置了异常，那么它就是 完成 。

  `cancelled`()

    如果期程已 取消 返回 `True`

    这个方法通常在设置结果或异常前用来检查期程是否已 取消 。

        if not fut.cancelled():
            fut.set_result(42)

  `add_done_callback`(callback, *, context=None)

    添加一个在期程 完成 时运行的回调函数。

    调用 callback 时，期程对象是它的唯一参数。

    调用这个方法时期程已经 完成 , 回调函数已被 `loop.call_soon()` 调度。

    可选键值类的参数 context 允许 callback 运行在一个指定的自定义 `contextvars.Context` 对象中。如果没有提供 context ，则使用当前上下文。

    可以用 `functools.partial()` 给回调函数传递参数，例如:

        # Call 'print("Future:", fut)' when "fut" is done.
        fut.add_done_callback(
            functools.partial(print, "Future:"))

    在 3.7 版更改: 加入键值类形参 context。请参阅 PEP 567 查看更多细节。

  `remove_done_callback`(callback)

    从回调列表中移除 callback 。

    返回被移除的回调函数的数量，通常为1，除非一个回调函数被添加多次。

  `cancel`()

    取消期程并调度回调函数。

    如果期程已经 完成 或 取消 ，返回 `False` 。否则将期程状态改为 取消 并在调度回调函数后返回 `True` 。

  `exception`()

    返回期程已设置的异常。

    只有期程在 完成 时才返回异常(或者 `None` ，如果没有设置异常 )。

    如果期程已 取消，方法会引发一个 `CancelledError` 异常。

    如果期程还没 完成 ，这个方法会引发一个 `InvalidStateError` 异常。

  `get_loop`()

    返回期程对象已绑定的事件循环。

    3.7 新版功能.

这个例子创建一个期程对象，创建和调度一个异步作业去设置期程结果，然后等待期程的结果:

    async def set_after(fut, delay, value):
        # Sleep for *delay* seconds.
        await asyncio.sleep(delay)

        # Set *value* as a result of *fut* Future.
        fut.set_result(value)

    async def main():
        # Get the current event loop.
        loop = asyncio.get_running_loop()

        # Create a new Future object.
        fut = loop.create_future()

        # Run "set_after()" coroutine in a parallel Task.
        # We are using the low-level "loop.create_task()" API here because
        # we already have a reference to the event loop at hand.
        # Otherwise we could have just used "asyncio.create_task()".
        loop.create_task(
            set_after(fut, 1, '... world'))

        print('hello ...')

        # Wait until *fut* has a result (1 second) and print it.
        print(await fut)

    asyncio.run(main())

重要

该期程对象是为了模仿 `concurrent.futures.Future` 。主要差异包含：

- `concurrent.futures.Future` 实例不能像asyncio期程那样等待。

- `asyncio.Future.result()` 和 `asyncio.Future.exception()` 不接受 timeout 参数。

- 期程没有 完成 时 `asyncio.Future.result()` 和 `asyncio.Future.exception()` 引发 `InvalidStateError` 引发一个异常。

- 使用 `asyncio.Future.add_done_callback()` 注册的回调函数不会立即调用，而是被 `loop.call_soon()` 调度。

- asyncio期程不能兼容 `concurrent.futures.wait()` 和 `concurrent.futures.as_completed()` 函数。