-
-
Notifications
You must be signed in to change notification settings - Fork 34.7k
gh-151213: Document asyncio debugging tools #151392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
johnslavik
wants to merge
11
commits into
python:main
Choose a base branch
from
johnslavik:gh-151213-document-asyncio-debugging-tools
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+177
−1
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
22a4cf0
Document asyncio introspection tools
johnslavik 2a8afdf
Add separator line after source code reference
johnslavik 397ae6c
gh-151213: Improve What's New prose and add cycle detection to asynci…
johnslavik 33a8976
gh-151213: Revert accidental What's New rewrite
johnslavik 35ad424
gh-151213: Improve asyncio-tools reference docs
johnslavik a2f456f
gh-151213: Tweak asyncio introspection intro
johnslavik 3155e2c
Clarify asyncio ps output description
johnslavik e004d5d
Reorder asyncio introspection command docs
johnslavik 7fbc90e
Explain asyncio introspection retries inline
johnslavik 04d035b
Align asyncio CLI intro with module docs
johnslavik 23e19e8
Apply suggestions from code review
johnslavik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| .. currentmodule:: asyncio | ||
|
|
||
| .. _asyncio-introspection-tools: | ||
|
|
||
| ================================ | ||
| Command-line introspection tools | ||
| ================================ | ||
|
|
||
| **Source code:** :source:`Lib/asyncio/tools.py` | ||
|
|
||
| ------------------------------------- | ||
|
|
||
| The :mod:`!asyncio` module can be invoked as a script via ``python -m | ||
| asyncio`` to inspect the task graph of another running Python process without | ||
| modifying it or restarting it. The :mod:`!asyncio.tools` submodule implements | ||
| this interface. | ||
|
|
||
| The following commands inspect the process identified by ``PID``: | ||
|
|
||
| .. code-block:: shell-session | ||
|
|
||
| $ python -m asyncio pstree [--retries N] PID | ||
| $ python -m asyncio ps [--retries N] PID | ||
|
|
||
| The commands read the target process state without executing any code in it. | ||
| They are only available on supported platforms and may require permission to | ||
| inspect another process. See the :ref:`permission-requirements` for details. | ||
|
|
||
| .. seealso:: | ||
|
|
||
| :ref:`asyncio-graph` | ||
| Programmatic APIs for inspecting the async call graph of a task or | ||
| future in the current process. | ||
|
|
||
| The command examples below use this program, which creates a task hierarchy | ||
| suitable for inspection and prints its process ID: | ||
|
|
||
| .. code-block:: python | ||
|
johnslavik marked this conversation as resolved.
|
||
| :caption: 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()) | ||
|
|
||
| Run the program in one terminal and leave it running: | ||
|
|
||
| .. code-block:: shell-session | ||
|
|
||
| $ python example.py | ||
| PID: 12345 | ||
|
|
||
| Then pass the printed process ID to the commands from another terminal. | ||
| Thread IDs, task IDs, file paths, and line numbers vary between runs and | ||
| source layouts. | ||
|
|
||
| .. versionadded:: 3.14 | ||
|
|
||
| Command-line options | ||
| ==================== | ||
|
|
||
| .. option:: pstree PID | ||
|
|
||
| Display task and coroutine relationships as a tree. Each task is shown | ||
| with its full coroutine stack, nested under the task (if any) that is | ||
| awaiting it. This subcommand is useful for quickly identifying which branch | ||
| of a task hierarchy is blocked and where in its coroutine stack execution | ||
| has paused: | ||
|
|
||
| .. code-block:: shell-session | ||
|
|
||
| $ 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 | ||
|
|
||
| If the await graph contains a cycle, ``pstree`` reports an error instead | ||
| of printing a tree. A cycle in the await graph is unusual and typically | ||
| indicates a programming error: | ||
|
|
||
| .. code-block:: shell-session | ||
|
|
||
| $ python -m asyncio pstree 12345 | ||
| ERROR: await-graph contains cycles - cannot print a tree! | ||
|
|
||
| cycle: Task-2 → Task-3 → Task-2 | ||
|
|
||
| .. option:: ps PID | ||
|
|
||
| Display a flat table of all pending tasks in the process *PID*. Each row | ||
| shows the event-loop thread ID, task ID and name, coroutine stack, and the | ||
| awaiting task's stack, name, and ID, if any. | ||
|
|
||
| This subcommand prints all tasks regardless of whether the await graph | ||
| contains cycles: | ||
|
|
||
| .. code-block:: shell-session | ||
|
|
||
| $ 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 | ||
|
|
||
| .. option:: --retries N | ||
|
|
||
| Retry failed attempts to inspect the target process up to *N* times. This | ||
| can help when the target process changes while its state is being read. | ||
|
|
||
| .. versionadded:: 3.15 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the submodule is not documented, I'd prefer to keep that private for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, it may be better to document it as private, as currently it is technically public per PEP 387.