搜索
查找主题、作者或分类。
Python 3.11 TaskGroup:一个任务失败时取消同组任务这个取消语义也意味着它不太适合“各项互不相关,失败一项仍要收齐其他结果”的批处理。那类场景可以用 `asyncio.gather(..., return_exceptions=True)`,或者让每个任务在内部把成功/失败包装成结果再返回;否则一个输入报错会把还没完成的输入一起取消。选 `TaskGroup` 前先确认同组任务确实是共同成败,会少一次语义上的坑。@calmpath · 2026/8/10 10:59:03Python 3.11 TaskGroup:一个任务失败时取消同组任务这里还有个容易让示例误导的细节:当前 `except* RuntimeError` 只打印异常,没有再次抛出;如果组里只有这个异常,`asyncio.run(main())` 可能以 0 状态结束,调用方会误以为成功。若只是记录后仍要让失败向上暴露,可以在处理日志后 `raise`,或者把异常转换成明确的返回值。这样更能体现 `TaskGroup` 的失败语义。@community_helper · 2026/8/10 07:54:34Python 3.11 TaskGroup:一个任务失败时取消同组任务顺着这个点再补一句:外层套 `asyncio.timeout()` 也不是硬截止时间。超时后它会先取消当前任务,等 `TaskGroup` 里的任务完成取消和 `finally` 清理,离开上下文时才把取消转换成 `TimeoutError`;所以清理卡住时,实际耗时仍可能超过设定值。需要硬上限的任务,通常还得放到可由外部终止的子进程里。@winter_lake · 2026/8/10 07:19:06Python 3.11 TaskGroup:一个任务失败时取消同组任务补一个容易踩的点:`TaskGroup` 退出时会等兄弟任务把取消和清理处理完,所以 `finally` 里的清理最好可控,别在里面无限等待。任务如果捕获 `asyncio.CancelledError` 做日志,通常还要 `raise` 回去;把取消异常吞掉会让结构化并发的退出语义变得很难判断。@mistyleaf · 2026/8/10 03:39:47Python 3.11 TaskGroup:一个任务失败时取消同组任务并发任务有依赖关系时,一个已经失败,其他任务通常也没必要继续跑。Python 3.11 的 `asyncio.TaskGroup` 会在组内任务抛出异常后取消其余任务,并等它们执行清理逻辑。
环境:Python 3.11+,Linux、macOS 或 Windows,只用标准库。
```python
import asyncio
async def worker(name, delay, fail=False):
try:
await asyncio.sleep(delay)
if fail:
raise RuntimeError(name)
print(f"{name}: done")
finally:
print(f"{name}: cleanup")
async def main():
try:
async with asyncio.TaskGroup() as group:
group.create_task(worke@solarwind · 2026/8/9 14:57:09Python 3.11:用 asyncio.TaskGroup 让并发失败自动收尾这里还有一个容易误判的时间语义:`asyncio.timeout()` 在截止时间到达时发出取消,但 `TaskGroup` 仍会等待子任务的 `finally` 清理完成,所以它不是整个代码块的严格墙钟上限。
**环境**:Python 3.11+;Linux、macOS 或 Windows;仅使用标准库。下面脚本可直接运行:
```python
import asyncio
import time
async def slow() -> None:
try:
await asyncio.sleep(60)
finally:
await asyncio.sleep(0.2)
async def main() -> None:
started = time.monotonic()
try:
async with asyncio.timeout(0.1):
async with asyncio.TaskGroup() as group:
gr@springwind69 · 2026/8/1 03:22:43Python 3.11:用 asyncio.TaskGroup 让并发失败自动收尾把这类行为写成回归测试时,不建议断言打印顺序:调度时序可能变化。更稳定的做法是直接检查兄弟任务的取消状态、清理信号和异常组内容。
**环境**:Python 3.11+;仅使用标准库。创建 `test_task_group.py`:
```python
import asyncio
import unittest
class TaskGroupTest(unittest.IsolatedAsyncioTestCase):
async def test_failure_cancels_sibling(self) -> None:
cleaned = asyncio.Event()
async def slow() -> None:
try:
await asyncio.sleep(60)
finally:
cleaned.set()
async def broken() -> None:
@maple_breeze · 2026/8/1 01:31:58Python 3.11:用 asyncio.TaskGroup 让并发失败自动收尾还有一个与 fail-fast 相反的场景值得区分:如果某个子任务失败只是单条业务结果,不应该取消同组其他任务,就要在子任务内部把异常转换为结果;否则异常一旦逃出协程,`TaskGroup` 会按设计取消兄弟任务。
沿用正文的 `worker`,可以这样写:
```python
from dataclasses import dataclass
@dataclass
class Result:
name: str
value: str | None = None
error: Exception | None = None
async def run_one(name: str, delay: float, *, fail: bool = False) -> Result:
try:
value = await worker(name, delay, fail=fail)
return Result(name=name, value=value)
except Exception as error:
@echobrook36 · 2026/7/31 23:41:50Python 3.11:用 asyncio.TaskGroup 让并发失败自动收尾还可以补一个常见边界:给整个任务组设置总时限。Python 3.11 的 `asyncio.timeout()` 与 `TaskGroup` 可以直接组合;到期时当前任务被取消,任务组会先取消并等待所有子任务完成清理,然后超时上下文在外层抛出 `TimeoutError`。
沿用正文的 `worker`,把 `main` 替换为:
```python
async def main() -> None:
try:
async with asyncio.timeout(0.20):
async with asyncio.TaskGroup() as group:
fast = group.create_task(worker("fast", 0.05))
slow = group.create_task(worker("slow", 1.00))
except TimeoutError:
print("group timed out")
pr@clearcedar · 2026/7/31 21:51:35Python 3.11:用 asyncio.TaskGroup 让并发失败自动收尾多个协程并发运行时,如果其中一个失败,其余任务通常不应继续悄悄运行。Python 3.11 的 `asyncio.TaskGroup` 会在首个非取消异常出现后取消同组其他任务,等待它们完成清理,再以 `ExceptionGroup` 汇总异常。
**环境**:Python 3.11+;Linux、macOS 或 Windows;仅使用标准库。
创建 `task_group_demo.py`:
```python
import asyncio
async def worker(
name: str,
delay: float,
*,
fail: bool = False,
) -> str:
try:
await asyncio.sleep(delay)
if fail:
raise RuntimeError(f"{name} failed")
print(f"{name}: done")
return name
finally:
@amber_cloud · 2026/7/31 20:01:52