mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
new blogpost
This commit is contained in:
BIN
docs/blog/images/async-create-task.jpeg
Normal file
BIN
docs/blog/images/async-create-task.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 286 KiB |
26
docs/blog/posts/create-task-psa.md
Normal file
26
docs/blog/posts/create-task-psa.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
draft: true
|
||||||
|
date: 2023-02-11
|
||||||
|
categories:
|
||||||
|
- DevLog
|
||||||
|
authors:
|
||||||
|
- willmcgugan
|
||||||
|
---
|
||||||
|
|
||||||
|
# The Heisenbug lurking in your async code
|
||||||
|
|
||||||
|
I'm taking a brief break from blogging about [Textual](https://github.com/Textualize/textual) to bring you this brief PSA for Python developers who work with async code. I wanted to expand a little on this [tweet](https://twitter.com/Mtrl_Scientist/status/1624439847174676480).
|
||||||
|
|
||||||
|
<!-- more -->
|
||||||
|
|
||||||
|
If you have ever used `asyncio.create_task` you may have created a bug for yourself that is challenging (read *almost impossible*) to reproduce. If it occurs, your code will likely fail in unpredictable ways.
|
||||||
|
|
||||||
|
The root cause of this [Heisenbug](Heisenbug) is that if you don't hold a reference to the task object returned by `create_task` then the task may simply disappear, without warning, when Python runs garbage collection. This behavior is [well documented](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task), as you can see from this excerpt:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
But who reads all the docs? And who has perfect recall if they do? A search on GitHub indicates that there are a [lot of projects](https://github.com/search?q=%22asyncio.create_task%28%22&type=code) where this bug is waiting just for the right moment to ruin somebody's day.
|
||||||
|
|
||||||
|
I suspect the reason this mistake is so common is that tasks are a lot like threads (conceptually at least). With threads you can just launch them and forget. Unless you mark them as "daemon" threads they will exist for the lifetime of your app. Not so with Tasks.
|
||||||
|
|
||||||
|
The solution, as recommended in the docs, is to keep a reference to the task for as long as you need it to live. You could also use [TaskGroups](https://docs.python.org/3/library/asyncio-task.html#task-groups) which will keep references to your tasks. As long as all the tasks you spin up are in TaskGroups, you should be fine.
|
||||||
@@ -99,7 +99,10 @@ def take_svg_screenshot(
|
|||||||
async def auto_pilot(pilot: Pilot) -> None:
|
async def auto_pilot(pilot: Pilot) -> None:
|
||||||
app = pilot.app
|
app = pilot.app
|
||||||
await pilot.press(*press)
|
await pilot.press(*press)
|
||||||
|
await pilot.wait_for_scheduled_animations()
|
||||||
|
await pilot.pause()
|
||||||
svg = app.export_screenshot(title=title)
|
svg = app.export_screenshot(title=title)
|
||||||
|
|
||||||
app.exit(svg)
|
app.exit(svg)
|
||||||
|
|
||||||
svg = app.run(
|
svg = app.run(
|
||||||
|
|||||||
Reference in New Issue
Block a user