调用图内省

源代码: 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``,则所有条目都存在。如果 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(),但返回一个字符串。如果 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 或它们的子类的实例,否则该调用将不起作用。