调用图自省

源代码: Lib/asyncio/graph.py


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

在 3.14 版本加入。

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

为当前任务或提供的 TaskFuture 打印异步调用图。

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

此函数接收一个可选的 future 参数。如果未传入,将使用当前正在运行的任务。

如果此函数在 当前任务 上调用,可选的仅限关键字 depth 参数可用于跳过栈顶指定数量的帧。

如果提供了可选的仅限关键字 limit 参数,则结果图中的每个调用栈都将被截断,最多包含 abs(limit) 个条目。如果 limit 为正,则保留最接近调用点的条目。如果 limit 为负,则保留最顶部的条目。如果省略 limit 或为 None,则所有条目都存在。如果 limit0,则根本不会打印调用栈,只打印“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() 类似,但返回一个字符串。如果 futureNone 且没有当前任务,则此函数返回一个空字符串。

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

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

此函数接收一个可选的 future 参数。如果未传入,将使用当前正在运行的任务。如果没有当前任务,此函数返回 None

如果此函数在 当前任务 上调用,可选的仅限关键字 depth 参数可用于跳过栈顶指定数量的帧。

返回一个 FutureCallGraph 数据类对象

  • FutureCallGraph(future, call_stack, awaited_by)

    其中 future 是对 FutureTask(或其子类)的引用。

    call_stack 是一个由 FrameCallGraphEntry 对象组成的元组。

    awaited_by 是一个由 FutureCallGraph 对象组成的元组。

  • FrameCallGraphEntry(frame)

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

低级实用函数

为了自省异步调用图,asyncio 需要控制流结构(例如 shield()TaskGroup)的协作。任何时候涉及具有 Future.add_done_callback() 等低级 API 的中间 Future 对象时,都应该使用以下两个函数来告知 asyncio 这些中间 Future 对象与它们封装或控制的任务之间究竟是如何连接的。

asyncio.future_add_to_awaited_by(future, waiter, /)

记录 futurewaiter 等待。

futurewaiter 都必须是 FutureTask 或其子类的实例,否则调用将无效。

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

asyncio.future_discard_from_awaited_by(future, waiter, /)

记录 future 不再被 waiter 等待。

futurewaiter 都必须是 FutureTask 或其子类的实例,否则调用将无效。