调用图内省

源代码: Lib/asyncio/graph.py


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

Added in version 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。 任何时候涉及到具有底层 API (如 Future.add_done_callback()) 的中间 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 或它们的子类的实例,否则该调用将不起作用。