Skip to content

Latest commit

 

History

History
593 lines (397 loc) · 16.5 KB

27.协程-Future类详解.md

File metadata and controls

593 lines (397 loc) · 16.5 KB

Future类详解

一.Future的定义概览

定义: Future的本质是一个占位符对象,表示一个尚未完成的异步操作的结果。它允许您在异步操作完成后获取其结果或处理错误。

Future的状态: 其具有不同的状态

通常包括以下几种状态:

Pending(未完成): 初始状态,表示异步操作尚未完成。

Running(运行中): 表示异步操作正在执行。

Cancelled(已取消): 表示异步操作被取消,通常是由于超时或其他原因。

Finished(已完成): 表示异步操作已成功完成,具有一个结果值。

Errored(出错): 表示异步操作完成时出现错误。

创建: 通常通过asyncio.Future()或其他异步框架提供的类似方式来创建Future对象。

二.关于Future的几个方法

1.asyncio.isfuture

结构:

asyncio.isfuture(obj)

参数:

obj: 要检查的对象。

作用:

用于检查给定的对象是否是 asyncio 模块中的 asyncio.Future 或其子类的实例。如果是 asyncio.Future 的实例或其子类,该函数将返回 True,否则返回 False

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)

async def main():
    future = asyncio.create_task(my_coroutine())

    print(asyncio.isfuture(future))  # 输出 True
    print(asyncio.isfuture("Hello"))  # 输出 False

if __name__ == "__main__":
    asyncio.run(main())

2.asyncio.ensure_future

结构:

asyncio.ensure_future(coro, *, loop=None)

参数:

coro: 要包装成 Task 对象的协程函数(或可等待对象)。

loop: 可选参数,指定要使用的事件循环。如果不提供 loop 参数,则会使用当前默认的事件循环。

作用:

用于创建一个 Task 对象,表示一个异步任务。它的作用类似于 asyncio.create_task(),用于将协程函数包装成一个 Task 对象,以便能够在事件循环中调度执行。

注意:

asyncio.ensure_future() 返回一个 Task 对象,该对象表示了要执行的异步任务。与 asyncio.create_task() 不同,asyncio.ensure_future() 不会直接将任务添加到事件循环中,而是返回一个任务对象,您需要稍后手动添加到事件循环中,或者在 await 该任务时自动将其添加到事件循环中。

import asyncio


async def my_coroutine():
    await asyncio.sleep(1)
    return "Hello, World!"


async def main():
    # 使用 asyncio.ensure_future() 创建一个 Task 对象
    task = asyncio.ensure_future(my_coroutine())

    # 将任务添加到事件循环中
    result = await task

    print(result)  # 输出 "Hello, World!"


if __name__ == "__main__":
    asyncio.run(main())

3.asyncio.wrap_future

结构:

asyncio.wrap_future(future, loop=None)

参数:

future: 要包装的非异步 Future 对象。

loop: 可选参数,指定要使用的事件循环。如果不提供 loop 参数,则会使用当前默认的事件循环。

作用:

用于将一个非异步的 concurrent.futures.Future 或其他类似的 Future 对象包装成 asyncio.Future 对象,以便在 asyncio 中使用。这个函数通常用于将标准的concurrent.futures模块中的Future对象转换为asyncio模块中的Future对象,从而实现异步和协程的兼容性。

注意:

asyncio.wrap_future() 返回一个 asyncio.Future 对象,该对象表示了原始的非异步 Future 对象。这样,您可以在 asyncio 中使用非异步 Future 对象,并将其与协程和异步操作一起工作。

import asyncio
import concurrent.futures

def blocking_function():
    import time
    time.sleep(2)
    return "Hello, World!"

async def main():
    # 创建一个 concurrent.futures.Future 对象
    executor = concurrent.futures.ThreadPoolExecutor()
    future = executor.submit(blocking_function)

    # 使用 asyncio.wrap_future() 包装成 asyncio.Future 对象
    asyncio_future = asyncio.wrap_future(future)

    # 等待 asyncio.Future 完成
    result = await asyncio_future
    print(result)  # 输出 "Hello, World!"

if __name__ == "__main__":
    asyncio.run(main())

在这个示例中,我们首先创建了一个标准库 concurrent.futures.ThreadPoolExecutor 对象,然后使用 executor.submit() 启动一个阻塞函数 blocking_function()。接下来,我们使用 asyncio.wrap_future()concurrent.futures.Future 包装成 asyncio.Future,并在协程中等待其完成。这样,我们就能够在 asyncio 中与标准库中的 Future 对象一起使用。

三.Future对象的常用方法

1.result

结构:

result = future.result()

作用:

该方法用于获取 asyncio.Futureconcurrent.futures.Future 对象的结果值的常用方法。

这个方法的行为会根据 Future 对象的状态进行不同的处理:

如果 Future 对象已经成功完成(状态为 Finished),result() 方法将返回异步操作的结果值。

如果 Future 对象尚未完成(状态为 PendingRunning),result() 方法将阻塞当前协程或线程,等待操作完成,并返回结果值。

如果 Future 对象表示的操作出现错误(状态为 Errored),result() 方法将引发相应的异常,通常是 asyncio.CancelledError 或其他异常,以指示操作失败。

注意

在使用 result() 方法时,特别是在异步程序中,应该小心处理可能的异常,以避免程序中断。通常,最好使用 try/except 块来捕获和处理异常,以确保程序的稳定性。

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)
    return "Hello, World!"

async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 启动异步操作
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_result(task.result())
    )

    try:
        # 等待 asyncio.Future 完成并获取结果
        result = future.result()
        print(result)  # 输出 "Hello, World!"
    except asyncio.CancelledError:
        print("The task was cancelled.")
    except Exception as e:
        print("An error occurred:", e)

if __name__ == "__main__":
    asyncio.run(main())

2.set_result

结构:

future.set_result(result)

参数:

result: 要设置的异步操作的结果值

作用:

用于将结果值设置到 asyncio.Future 对象中的方法。asyncio.Future 是用于表示异步操作结果的对象,通过 set_result() 方法,您可以将异步操作的结果设置为成功完成,并将结果值存储在 Future 对象中。

注意:

使用 set_result() 方法时,通常应该确保操作已成功完成,因为这个方法会将 Future 对象的状态从未完成(Pending)更改为已完成(Finished),并存储结果值。如果操作未完成或出现错误,可能会引发异常。

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)
    return "Hello, World!"

async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 启动异步操作
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_result(task.result())
    )

    # 等待 asyncio.Future 完成
    result = await future
    print(result)  # 输出 "Hello, World!"

if __name__ == "__main__":
    asyncio.run(main())

3.set_exception

结构:

future.set_exception(exception)

参数:

exception: 要设置的异常对象,通常是一个 Exception 子类的实例,用于表示操作的错误原因。

作用:

用于将异常设置到 asyncio.Future 对象中的方法。asyncio.Future 通常用于表示异步操作的结果,而 set_exception() 方法允许您将异常信息与该结果关联起来,以表示异步操作的错误状态。

注意:

使用 set_exception() 方法时,通常应确保操作已出错,因为这个方法会将 Future 对象的状态从未完成(Pending)更改为已完成(Errored),并存储异常对象。

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)
    raise ValueError("An error occurred")

async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 启动异步操作,此处故意引发异常
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_exception(task.exception())
    )

    try:
        # 等待 asyncio.Future 完成
        await future
    except asyncio.CancelledError:
        print("The task was cancelled.")
    except Exception as e:
        print("An error occurred:", e)  # 输出 "An error occurred: An error occurred"

if __name__ == "__main__":
    asyncio.run(main())

4.done

结构:

done = future.done()

作用:

用于检查异步操作是否已经完成。asyncio.Future 通常用于表示异步操作的结果,而 done() 方法用于查询操作的状态。

如果 Future 对象已经成功完成(状态为 Finished),则返回 True

如果 Future 对象尚未完成(状态为 PendingRunning),则返回 False

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)
    return "Hello, World!"

async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 启动异步操作
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_result(task.result())
    )

    # 检查 asyncio.Future 是否已完成
    if not future.done():
        print("Future is not yet done.")
    else:
        result = future.result()
        print("Future result:", result)  # 输出 "Future result: Hello, World!"

if __name__ == "__main__":
    asyncio.run(main())

5.cancelled

结构:

cancelled = future.cancelled()

作用:

用于检查异步操作是否已被取消。asyncio.Future 通常用于表示异步操作的结果,而 cancelled() 方法用于查询操作是否被取消。

如果 Future 对象已被取消,返回 True

如果 Future 对象尚未被取消或已经完成,返回 False

通常,在协程或异步任务中,您可以使用 cancelled() 方法来检查操作是否被取消,并根据需要采取相应的操作。如果操作被取消,您可以处理取消的情况,例如清理资源或执行其他必要的操作。

import asyncio


async def my_coroutine():
    try:
        await asyncio.sleep(1)
    except asyncio.CancelledError:
        print("Coroutine was cancelled")


async def main():
    task = asyncio.create_task(my_coroutine())
    await asyncio.sleep(0.5)  # 在0.5秒后取消任务
    task.cancel()

    if task.cancelled():
        print("Task was cancelled")
    else:
        print("Task was not cancelled")


if __name__ == "__main__":
    asyncio.run(main())

6.add_done_callback

结构:

future.add_done_callback(callback)

参数:

callback: 要添加的回调函数,通常是一个接受一个参数的可调用对象,该参数是 Future 对象本身。

作用:

用于添加一个回调函数,该回调函数会在 Future 对象完成(成功或出错)时被调用。回调函数会接收一个参数,即 Future 对象本身,允许您在异步操作完成后执行特定的操作或处理结果。

add_done_callback() 方法允许您注册一个回调函数,以便在 Future 对象的状态发生变化时执行特定的操作。这在异步编程中很有用,可以用于处理操作完成后的清理、通知或其他异步操作。

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)
    return "Hello, World!"

def callback(future):
    if future.cancelled():
        print("Future was cancelled")
    elif future.done() and not future.cancelled():
        result = future.result()
        print("Future result:", result)

async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 添加回调函数
    future.add_done_callback(callback)

    # 启动异步操作
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_result(task.result())
    )

    try:
        # 等待 asyncio.Future 完成
        await future
    except asyncio.CancelledError:
        print("Future was cancelled")

if __name__ == "__main__":
    asyncio.run(main())

7.cancel

结构:

future.cancel()

作用:

用于取消异步操作,即将与 Future 关联的协程或任务标记为取消状态。这个方法允许您在某些情况下停止异步操作的执行。

当调用 cancel() 方法时,会发生以下情况:

如果 Future 对象尚未完成(状态为 PendingRunning),则将其状态更改为已取消(Cancelled)。

如果 Future 对象已经完成(状态为 FinishedErrored),则取消操作不会生效,因为已经完成的操作无法取消。

一旦异步操作被取消,协程或任务会在适当的时候引发 asyncio.CancelledError 异常,以通知操作已被取消。您可以在协程内部捕获这个异常并执行适当的处理。

import asyncio


async def my_coroutine():
    try:
        await asyncio.sleep(1)
        print("Coroutine completed")
    except asyncio.CancelledError:
        print("Coroutine was cancelled")


async def main():
    # 启动异步操作
    task = asyncio.create_task(my_coroutine())
    await asyncio.sleep(0.4)
    task.cancel()

    # 去报任务被取消

    if task.cancelled():
        print("task was cancelled")
    else:
        print("task was not cancelled")


if __name__ == "__main__":
    asyncio.run(main())

8.exception

结构:

exc = future.exception()

作用:

用于获取异步操作引发的异常。asyncio.Future 通常用于表示异步操作的结果,如果操作失败或出现异常,可以使用 exception() 方法获取异常信息。

exception() 方法返回一个异常对象:

如果 Future 对象尚未完成或成功完成(状态为 PendingRunningFinished),或者未引发异常,则返回 None

如果 Future 对象已完成且引发了异常(状态为 Errored),则返回引发的异常对象。

通常,您可以使用 exception() 方法来检查异步操作是否引发了异常,并根据需要处理异常情况。

import asyncio

async def my_coroutine():
    await asyncio.sleep(1)
    raise ValueError("An error occurred")

async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 启动异步操作,此处故意引发异常
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_exception(task.exception())
    )

    try:
        # 等待 asyncio.Future 完成
        await future
    except asyncio.CancelledError:
        print("Future was cancelled")
    except Exception as e:
        print("An error occurred:", e)  # 输出 "An error occurred: An error occurred"

    # 获取并输出异常信息
    exception = future.exception()
    if exception is not None:
        print("Exception:", exception)  # 输出 "Exception: An error occurred"

if __name__ == "__main__":
    asyncio.run(main())

9.get_loop

结构:

loop = future.get_loop()

作用:

用于获取与该 Future 关联的事件循环(event loop)。这个方法返回与 Future 对象相关联的事件循环对象,如果未关联任何事件循环,则返回 None

import asyncio


async def my_coroutine():
    await asyncio.sleep(1)
    return "Hello, World!"


async def main():
    # 创建一个 asyncio.Future 对象
    future = asyncio.Future()

    # 启动异步操作
    asyncio.create_task(my_coroutine()).add_done_callback(
        lambda task: future.set_result(task.result())
    )

    try:
        # 等待 asyncio.Future 完成
        await future
    except asyncio.CancelledError:
        print("Future was cancelled")

    # 获取并输出与 Future 关联的事件循环
    future_loop = future.get_loop()
    if future_loop is not None:
        print("Future is associated with the event loop.")
    else:
        print("Future is not associated with any event loop.")


if __name__ == "__main__":
    asyncio.run(main())