doc: 阅读python文档
This commit is contained in:
161
python/py.md
161
python/py.md
@@ -120,6 +120,15 @@
|
||||
- [iterators](#iterators)
|
||||
- [generators](#generators)
|
||||
- [generator expression](#generator-expression)
|
||||
- [asyncio](#asyncio)
|
||||
- [Coroutines](#coroutines)
|
||||
- [Awaitables](#awaitables)
|
||||
- [Coroutinues](#coroutinues)
|
||||
- [Tasks](#tasks)
|
||||
- [Futures](#futures)
|
||||
- [Creating Tasks](#creating-tasks)
|
||||
- [`asyncio.create_task(coro, *, name=None, context=None)`](#asynciocreate_taskcoro--namenone-contextnone)
|
||||
- [Task Cancellation](#task-cancellation)
|
||||
|
||||
|
||||
# Python
|
||||
@@ -2035,3 +2044,155 @@ generator令iterator的编写更加简单。
|
||||
>>> list(data[i] for i in range(len(data)-1, -1, -1))
|
||||
['f', 'l', 'o', 'g']
|
||||
```
|
||||
|
||||
## asyncio
|
||||
python支持通过`async/await`语法编写并发代码。asyncio是多个python异步框架的基础。
|
||||
|
||||
### Coroutines
|
||||
可以通过`async/await`的语法来编写asyncio application。例如,如下代码将打印`hello`并等待1s,然后打印`world`:
|
||||
```py
|
||||
>>> import asyncio
|
||||
|
||||
>>> async def main():
|
||||
print('hello')
|
||||
await asyncio.sleep(1)
|
||||
print('world')
|
||||
|
||||
>>> asyncio.run(main())
|
||||
hello
|
||||
world
|
||||
```
|
||||
如果仅简单调用`main()`,并不会对该coroutinue进行调度:
|
||||
```py
|
||||
>>> main()
|
||||
<coroutine object main at 0x1053bb7c8>
|
||||
```
|
||||
|
||||
为了实际的运行coroutinue,asyncio提供了如下机制:
|
||||
- `asyncio.run`:在上述示例中,`asyncio.run`用于执行main函数的entry point
|
||||
- `awaiting on coroutinue`:如下代码片段将会在1s后打印`hello`,并在2s后打印`world`
|
||||
```py
|
||||
import asyncio
|
||||
import time
|
||||
|
||||
async def say_after(delay, what):
|
||||
await asyncio.sleep(delay)
|
||||
print(what)
|
||||
|
||||
async def main():
|
||||
print(f"started at {time.strftime('%X')}")
|
||||
|
||||
await say_after(1, 'hello')
|
||||
await say_after(2, 'world')
|
||||
|
||||
print(f"finished at {time.strftime('%X')}")
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
上述示例总共耗费3s,首先等待`hello` 1s,再等待`world` 2s
|
||||
- `asyncio.create_task()`:该方法支持创建Tasks让多个coroutinue并发运行
|
||||
```py
|
||||
async def main():
|
||||
task1 = asyncio.create_task(
|
||||
say_after(1, 'hello'))
|
||||
|
||||
task2 = asyncio.create_task(
|
||||
say_after(2, 'world'))
|
||||
|
||||
print(f"started at {time.strftime('%X')}")
|
||||
|
||||
# Wait until both tasks are completed (should take
|
||||
# around 2 seconds.)
|
||||
await task1
|
||||
await task2
|
||||
|
||||
print(f"finished at {time.strftime('%X')}")
|
||||
```
|
||||
上述示例总共耗费2s,等待`hello` 1s,`hello`打印后再过1s打印`world`
|
||||
|
||||
- `asyncio.TaskGroup`:该方法相较`asyncio.create_task`提供了一个更加现代的api,示例如下:
|
||||
```py
|
||||
async def main():
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
task1 = tg.create_task(
|
||||
say_after(1, 'hello'))
|
||||
|
||||
task2 = tg.create_task(
|
||||
say_after(2, 'world'))
|
||||
|
||||
print(f"started at {time.strftime('%X')}")
|
||||
|
||||
# The await is implicit when the context manager exits.
|
||||
|
||||
print(f"finished at {time.strftime('%X')}")
|
||||
```
|
||||
当前示例总体耗时也为2s
|
||||
|
||||
### Awaitables
|
||||
当对象可以在await表达式中使用时,该对象被称为Awaitable object。许多asyncio api被定义为接收awaitable object。
|
||||
|
||||
总共有3中awaitables:`coroutinue, Tasks, Futures`
|
||||
|
||||
#### Coroutinues
|
||||
python中coroutinue是awaitable,并且可以在其他coroutinue中通过`await`调用:
|
||||
```py
|
||||
import asyncio
|
||||
|
||||
async def nested():
|
||||
return 42
|
||||
|
||||
async def main():
|
||||
# Nothing happens if we just call "nested()".
|
||||
# A coroutine object is created but not awaited,
|
||||
# so it *won't run at all*.
|
||||
nested() # will raise a "RuntimeWarning".
|
||||
|
||||
# Let's do it differently now and await it:
|
||||
print(await nested()) # will print "42".
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
#### Tasks
|
||||
`Tasks`用于并发的对coroutinues进行调度。
|
||||
|
||||
当通过`asyncio.create_task()`将coroutinue封装在Task中时,coroutinue将会自动的被调度:
|
||||
```py
|
||||
import asyncio
|
||||
|
||||
async def nested():
|
||||
return 42
|
||||
|
||||
async def main():
|
||||
# Schedule nested() to run soon concurrently
|
||||
# with "main()".
|
||||
task = asyncio.create_task(nested())
|
||||
|
||||
# "task" can now be used to cancel "nested()", or
|
||||
# can simply be awaited to wait until it is complete:
|
||||
await task
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
#### Futures
|
||||
`Future`是一个底层的awaitable对象,代表一个异步操作的最终结果。
|
||||
|
||||
当一个Future对象被awaited时,代表coroutinue将会等待,直至Future执行完成。
|
||||
|
||||
### Creating Tasks
|
||||
#### `asyncio.create_task(coro, *, name=None, context=None)`
|
||||
将coroutinue封装在Task对象中,并且对其进行调度。该方法会返回一个Task object。
|
||||
|
||||
该task将会在`get_running_loop()`返回的loop中执行,如果当前线程中没有running loop,那么将会抛出`RuntimeError`。
|
||||
|
||||
### Task Cancellation
|
||||
task可以被简单和安全的取消。当task被取消时,并不会立马中断task抛出`asyncio.CancelledError`,而是等到task下一次执行await时才会抛出异常。
|
||||
|
||||
推荐通过`try/finally`来执行clean-up逻辑,当显式捕获的`asyncio.CancelledError`时,通常在clean-up操作完成后都应该对异常重新抛出。
|
||||
|
||||
asyncio中存在部分组件允许结构化的并发,例如`asyncio.TaskGroup`,其内部实现中使用了cancellation,`如果coroutinue吞了异常,将会导致asyncio中TaskGroup等组件行为异常`。
|
||||
|
||||
类似的,用户代码中通常也不应该调用`uncancel`。
|
||||
|
||||
但是,如果真的需要对`asyncio.CancelledError`进行suppress,其在吞异常之后还需要调用`uncancel`来取消cancellation state。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user