doc: 阅读python await/async文档

This commit is contained in:
asahi
2025-08-19 20:57:23 +08:00
parent ecd049c842
commit c20bea9ea7

View File

@@ -129,6 +129,16 @@
- [Creating Tasks](#creating-tasks)
- [`asyncio.create_task(coro, *, name=None, context=None)`](#asynciocreate_taskcoro--namenone-contextnone)
- [Task Cancellation](#task-cancellation)
- [Task Groups](#task-groups)
- [`asyncio.TaskGroup`](#asynciotaskgroup)
- [`taskgroup.create_task(coro, *, name=None, context=None)`](#taskgroupcreate_taskcoro--namenone-contextnone)
- [CancelledError](#cancellederror)
- [terminate a taskgroup](#terminate-a-taskgroup)
- [Sleeping](#sleeping)
- [`async asyncio.sleep(delay, result=None)`](#async-asynciosleepdelay-resultnone)
- [并发运行任务](#并发运行任务)
- [`awaitable asyncio.gather(*aws, return_exceptions=False)`](#awaitable-asynciogatheraws-return_exceptionsfalse)
- [return\_exceptions](#return_exceptions)
# Python
@@ -2196,3 +2206,146 @@ asyncio中存在部分组件允许结构化的并发例如`asyncio.TaskGroup`
但是,如果真的需要对`asyncio.CancelledError`进行suppress其在吞异常之后还需要调用`uncancel`来取消cancellation state。
### Task Groups
task groups整合了`task creation API`和`wait for all tasks in the group to finish`两方面,使异步代码的编写变得更加便捷。
#### `asyncio.TaskGroup`
该类是一个asynchronous context manager其中持有了一组taskstask可以通过`create_task`被添加到group中。当context manager退出时会等待所有的tasks执行完成。
##### `taskgroup.create_task(coro, *, name=None, context=None)`
该方法调用会在group中创建一个task该方法的签名和`asyncio.create_task`方法的一致。
> 如果该task group是非活跃的那么将会对给定的coro进行关闭。
task group的使用示例如下所示
```py
async def main():
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(some_coro(...))
task2 = tg.create_task(another_coro(...))
print(f"Both tasks have completed now: {task1.result()}, {task2.result()}")
```
`async with`语句会等待所有位于task group中的tasks都执行完成但是`在等待的过程中仍然可以向task group中添加新的task`。
> 可以将task group传递给coroutinue并且在corotinue中调用`tg.create_task`向task group中添加task
一旦task group中所有的task执行完成并且`async with`block退出那么将无法向task group中添加新的task。
##### CancelledError
一旦task group中任一task抛出`非CancelledError的异常`位于task group中的其他task都会被cancelled后续任何task都无法被添加到task group中。
并且,`除了添加到task group的tasks之外包含`async with`代码块的`main task`也会被标记为cancelled。`
task group抛出非`CancelledError`会导致在下一个await表达式时抛出`CancelledError`异常,但是,`CancelledError`并不会抛出`async with block`故而在async with block外无需关注async with是否会抛出`CancelledError`。
当所有task都完成后任何抛出`非CancelledError类似异常`的异常都会被整合到`ExceptionGroup`/`BaseExceptionGroup`中,并被后续抛出。
有两种异常将会被特殊对待:`KeyboardInterrupt`和`SystemExit`对于这两种异常task group仍然会取消其他task并且等待其余tasks但是原始的`KeyboardInterrupt`和`SystemExit`异常仍然会被抛出。抛出的是异常的原值而不是ExceptionGroup
对于async with body中抛出的异常其处理和task抛出异常一致。
#### terminate a taskgroup
在python标准库中并不原生支持对task group的终止。但是可以通过向task group中`添加一个抛出未处理异常的task`来实现,示例如下:
```py
import asyncio
from asyncio import TaskGroup
class TerminateTaskGroup(Exception):
"""Exception raised to terminate a task group."""
async def force_terminate_task_group():
"""Used to force termination of a task group."""
raise TerminateTaskGroup()
async def job(task_id, sleep_time):
print(f'Task {task_id}: start')
await asyncio.sleep(sleep_time)
print(f'Task {task_id}: done')
async def main():
try:
async with TaskGroup() as group:
# spawn some tasks
group.create_task(job(1, 0.5))
group.create_task(job(2, 1.5))
# sleep for 1 second
await asyncio.sleep(1)
# add an exception-raising task to force the group to terminate
group.create_task(force_terminate_task_group())
except* TerminateTaskGroup:
pass
asyncio.run(main())
```
其输出如下:
```py
Task 1: start
Task 2: start
Task 1: done
```
### Sleeping
#### `async asyncio.sleep(delay, result=None)`
该方法会阻塞`delay`秒。
如果`result`有值那么当coroutinue完成时result会被返回给调用方。
sleep会一直挂起当前任务允许其他任务执行。如果为sleep传参为0其将会让其他tasks执行可作为一种优化手段。其通常是在运行时间较长的任务中使用避免长任务一直占用event loop。
```py
await sleep(0)
```
### 并发运行任务
#### `awaitable asyncio.gather(*aws, return_exceptions=False)`
并发的运行aws中的awaitable objects。
如果aws中的某个awaitable是coroutinue那么其将自动作为task被调度。
如果所有的awaitable objects都成功执行那么结果将会聚合到returned list中。returned list中结果的顺序和aws中awaitable object的顺序一致。
##### return_exceptions
return_exceptions的值决定了gather的行为
- `False`默认如果该参数为False那么那么aws中抛出的第一个异常将会被立刻传递到`等待gather返回结果的task`aws中其他的tasks并不会被cancelled仍然会继续运行
- `True`exceptions也将被当作成功的返回结果并且被组装到returned list中
如果`gather()`被cancelled那么gather中所有未完成的awaitable objects也都会被取消。
如果aws中的任一Task或Future被取消其将被看作抛出CancelledError在这种情况下`gather()`并不会被cancelled。这样能够避免某一个task/future的取消造成gather中其他的task/future也被取消。
`asyncio.gather`的使用示例如下所示:
```py
import asyncio
async def factorial(name, number):
f = 1
for i in range(2, number + 1):
print(f"Task {name}: Compute factorial({number}), currently i={i}...")
await asyncio.sleep(1)
f *= i
print(f"Task {name}: factorial({number}) = {f}")
return f
async def main():
# Schedule three calls *concurrently*:
L = await asyncio.gather(
factorial("A", 2),
factorial("B", 3),
factorial("C", 4),
)
print(L)
asyncio.run(main())
# Expected output:
#
# Task A: Compute factorial(2), currently i=2...
# Task B: Compute factorial(3), currently i=2...
# Task C: Compute factorial(4), currently i=2...
# Task A: factorial(2) = 2
# Task B: Compute factorial(3), currently i=3...
# Task C: Compute factorial(4), currently i=3...
# Task B: factorial(3) = 6
# Task C: Compute factorial(4), currently i=4...
# Task C: factorial(4) = 24
# [2, 6, 24]
```