# 调用图内省

源代码: Lib/asyncio/graph.py

asyncio 具有强大的运行时调用图内省工具，可以跟踪正在运行的 协程 或 任务 或挂起的 future 的整个调用图。这些工具和底层机制可以在 Python 程序中使用，也可以由外部性能分析器和调试器使用。

Added in version 3.14.

asyncio.print_call_graph(future=None, /, *, file=None, depth=1, limit=None)

  打印当前任务或提供的 `Task` 或 `Future` 的异步调用图。

  此函数从顶部帧开始打印条目，并向下打印到调用点。

  该函数接收一个可选的 future 参数。如果没有传入，则使用当前运行的任务。

  如果在 当前任务 上调用该函数，可选的仅限关键字 depth 参数可用于从堆栈顶部跳过指定的帧数。

  如果提供了可选的仅限关键字 limit 参数，则结果图中的每个调用堆栈将被截断，以最多包含 `abs(limit)` 项。如果 limit 为正数，则剩下的条目是最接近调用点的。如果 limit 为负数，则保留最上面的项。如果 limit 省略或为 `None`，则所有条目都存在。如果 limit 为 `0`，则根本不打印调用堆栈，只打印“awaited by”信息。

  如果 file 省略或为 `None`，该函数将打印到 `sys.stdout`。

  示例:

  以下 Python 代码：

      import asyncio

      async def test():
          asyncio.print_call_graph()

      async def main():
          async with asyncio.TaskGroup() as g:
              g.create_task(test(), name='test')

      asyncio.run(main())

  将打印:

      * Task(name='test', id=0x1039f0fe0)
      + Call stack:
      |   File 't2.py', line 4, in async test()
      + Awaited by:
         * Task(name='Task-1', id=0x103a5e060)
            + Call stack:
            |   File 'taskgroups.py', line 107, in async TaskGroup.__aexit__()
            |   File 't2.py', line 7, in async main()

asyncio.format_call_graph(future=None, /, *, depth=1, limit=None)

  类似于 `print_call_graph()`，但返回一个字符串。如果 future 为 `None` 并且没有当前任务，则该函数返回一个空字符串。

asyncio.capture_call_graph(future=None, /, *, depth=1, limit=None)

  捕获当前任务或提供的 `Task` 或 `Future` 的异步调用图。

  该函数接收一个可选的 future 参数。如果没有传入，则使用当前运行的任务。如果当前没有任务，该函数返回 `None`。

  如果在 当前任务 上调用该函数，可选的仅限关键字 depth 参数可用于从堆栈顶部跳过指定的帧数。

  返回一个 `FutureCallGraph` 数据类对象：

  - `FutureCallGraph(future, call_stack, awaited_by)`

    > 其中 future 是一个指向 `Future` 或 `Task` (或其子类) 的引用。

    > `call_stack` 是一个 `FrameCallGraphEntry` 对象的元组。

    > `awaited_by` 是一个 `FutureCallGraph` 对象的元组。

  - `FrameCallGraphEntry(frame)`

    > 其中 frame 是调用栈中常规 Python 函数的帧对象。

## 底层实用工具函数

要内省一个异步调用图，asyncio 需要控制流结构的配合，比如 `shield()` 或 `TaskGroup`。 任何时候涉及到具有底层 API (如 `Future.add_done_callback()`) 的中间 `Future` 对象时，都应该使用以下两个函数来通知 asyncio 这些中间 Future 对象是如何与它们包装或控制的任务连接的。

asyncio.future_add_to_awaited_by(future, waiter, /)

  记录 future 被 waiter 等待。

  future 和 waiter 都必须是 `Future` 或 `Task` 或它们的子类的实例，否则该调用将不起作用。

  调用 `future_add_to_awaited_by()` 必须随后使用相同的参数最终调用 `future_discard_from_awaited_by()` 函数。

asyncio.future_discard_from_awaited_by(future, waiter, /)

  记录 future 不再被 waiter 等待。

  future 和 waiter 都必须是 `Future` 或 `Task` 或它们的子类的实例，否则该调用将不起作用。