命令行内省工具

源代码: Lib/asyncio/tools.py


asyncio 模块可以通过 python -m asyncio 作为脚本调用,用于检查另一个正在运行的 Python 进程的任务图,而无需修改或重启该进程。asyncio.tools 子模块实现了这一接口。

以下命令用于检查由 PID 标识的进程:

$ python -m asyncio pstree [--retries N] PID
$ python -m asyncio ps [--retries N] PID

这些命令只读取目标进程的状态,不会在其中执行任何代码。它们仅在受支持的平台上可用,并且可能需要获得检查另一进程的权限。详情请参阅 权限要求。

参见

Call graph introspection

用于检查当前进程中某个任务或 future 对象的异步调用图的编程接口。

下面的命令示例使用此程序,它创建了一个适合检查的任务层级结构,并打印出它的进程 ID:

example.py
import asyncio
import os

async def play(track):
    await asyncio.sleep(3600)
    print(f"🎵 Finished: {track}")

async def album(name, tracks):
    async with asyncio.TaskGroup() as tg:
        for track in tracks:
            tg.create_task(play(track), name=track)

async def main():
    print(f"PID: {os.getpid()}")
    async with asyncio.TaskGroup() as tg:
        tg.create_task(
            album("Sundowning", ["TNDNBTG", "Levitate"]),
            name="Sundowning",
        )
        tg.create_task(
            album("TMBTE", ["DYWTYLM", "Aqua Regia"]),
            name="TMBTE",
        )

asyncio.run(main())

在一个终端中运行该程序,并让它保持运行:

$ python example.py
PID: 12345

然后在另一个终端中把打印出来的进程 ID 传给这些命令。线程 ID、任务 ID、文件路径和行号会随每次运行以及源代码布局的不同而变化。

在 3.14 版本加入.

命令行选项

pstree PID

以树形结构显示任务与协程之间的关系。每个任务都会连同其完整的协程调用栈一起显示,并嵌套在等待它的任务(如果有)之下。该子命令有助于快速找出任务层级中哪个分支被阻塞,以及协程栈的执行停在了哪里:

$ python -m asyncio pstree 12345
└── (T) Task-1
    └──  main example.py:12
        └──  TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75
            └──  TaskGroup._aexit Lib/asyncio/taskgroups.py:124
                ├── (T) Sundowning
                │   └──  album example.py:7
                │       └──  TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75
                │           └──  TaskGroup._aexit Lib/asyncio/taskgroups.py:124
                │               ├── (T) TNDNBTG
                │               │   └──  play example.py:4
                │               │       └──  sleep Lib/asyncio/tasks.py:702
                │               └── (T) Levitate
                │                   └──  play example.py:4
                │                       └──  sleep Lib/asyncio/tasks.py:702
                └── (T) TMBTE
                    └──  album example.py:7
                        └──  TaskGroup.__aexit__ Lib/asyncio/taskgroups.py:75
                            └──  TaskGroup._aexit Lib/asyncio/taskgroups.py:124
                                ├── (T) DYWTYLM
                                │   └──  play example.py:4
                                │       └──  sleep Lib/asyncio/tasks.py:702
                                └── (T) Aqua Regia
                                    └──  play example.py:4
                                        └──  sleep Lib/asyncio/tasks.py:702

如果等待图(await graph)中存在环,pstree 会报错而不会打印树。等待图中出现环并不常见,通常意味着存在编程错误:

$ python -m asyncio pstree 12345
ERROR: await-graph contains cycles - cannot print a tree!

cycle: Task-2 → Task-3 → Task-2
ps PID

以扁平表格的形式显示进程 PID 中所有挂起的任务。每一行显示事件循环线程 ID、任务 ID 与名称、协程调用栈,以及等待它的任务的调用栈、名称和 ID(如果有)。

无论等待图中是否含有环,该子命令都会打印所有任务:

$ python -m asyncio ps 12345
tid        task id              task name            coroutine stack                                    awaiter chain                                      awaiter name    awaiter id
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
18445801   0x10a456060          Task-1               TaskGroup._aexit -> TaskGroup.__aexit__ -> main                                                                       0x0
18445801   0x10a439f60          Sundowning           TaskGroup._aexit -> TaskGroup.__aexit__ -> album   TaskGroup._aexit -> TaskGroup.__aexit__ -> main    Task-1          0x10a456060
18445801   0x10a439d70          TMBTE                TaskGroup._aexit -> TaskGroup.__aexit__ -> album   TaskGroup._aexit -> TaskGroup.__aexit__ -> main    Task-1          0x10a456060
18445801   0x10a2a3a80          TNDNBTG              sleep -> play                                      TaskGroup._aexit -> TaskGroup.__aexit__ -> album   Sundowning      0x10a439f60
18445801   0x10a2a38a0          Levitate             sleep -> play                                      TaskGroup._aexit -> TaskGroup.__aexit__ -> album   Sundowning      0x10a439f60
18445801   0x10a2d7150          DYWTYLM              sleep -> play                                      TaskGroup._aexit -> TaskGroup.__aexit__ -> album   TMBTE           0x10a439d70
18445801   0x10a6bdaa0          Aqua Regia           sleep -> play                                      TaskGroup._aexit -> TaskGroup.__aexit__ -> album   TMBTE           0x10a439d70
--retries N

重试检查目标进程的失败尝试,最多 N 次。当目标进程在被读取状态的过程中发生变化时,这会有所帮助。

在 3.15 版本加入.