呼叫圖內省(Call Graph Introspection)

原始碼:Lib/asyncio/graph.py


asyncio 擁有強大的 runtime 呼叫圖內省工具,可以追蹤執行中的協程任務,或是暫停的 future 的完整呼叫圖。這些工具和底層機制可以在 Python 程式內部使用,或被外部分析器和偵錯器使用。

在 3.14 版被加入.

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

印出目前任務或所提供的 TaskFuture 的非同步呼叫圖。

此函式會從頂層 frame 開始印出條目,然後往下到呼叫點。

此函式接受一個選擇性的 future 引數。如果未傳入,將使用目前執行中的任務。

如果在目前任務上呼叫此函式,可以使用選擇性的僅限關鍵字引數 depth 來跳過堆疊頂端指定數量的 frame。

如果提供了選擇性的僅限關鍵字引數 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 來跳過堆疊頂端指定數量的 frame。

會回傳一個 FutureCallGraph 資料類別物件:

  • FutureCallGraph(future, call_stack, awaited_by)

    其中 future 是對 FutureTask(或它們的子類別)的參照。

    call_stack 是一個由 FrameCallGraphEntry 物件組成的元組。

    awaited_by 是一個由 FutureCallGraph 物件組成的元組。

  • FrameCallGraphEntry(frame)

    其中 frame 是呼叫堆疊中常規 Python 函式的 frame 物件。

低階工具函式

要內省非同步呼叫圖,asyncio 需要來自控制流程結構的協作,例如 shield()TaskGroup。任何時候涉及使用低階 API(如 Future.add_done_callback())的中介 Future 物件時,應使用以下兩個函式來告知 asyncio 這些中介 future 物件如何與它們所包裝或控制的任務連接。

asyncio.future_add_to_awaited_by(future, waiter, /)

記錄 future 正被 waiter 等待。

futurewaiter 都必須是 FutureTask 或它們子類別的實例,否則呼叫將不會產生任何效果。

future_add_to_awaited_by() 的呼叫必須最終跟隨一個對 future_discard_from_awaited_by() 函式的呼叫,並使用相同的引數。

asyncio.future_discard_from_awaited_by(future, waiter, /)

記錄 future 不再被 waiter 等待。

futurewaiter 都必須是 FutureTask 或它們子類別的實例,否則呼叫將不會產生任何效果。