36. Coroutine và Async
36. Coroutine và Async
Coroutine là các phép tính có thể tiếp tục được sử dụng cho lập trình không đồng bộ. Họ để mã Python tạm dừng ở mứcawaitđiểm, đưa điều khiển trở lại vòng lặp sự kiện và sau đó tiếp tục lại khi thao tác được chờ đợi có kết quả.
Một coroutine tương tự như một trình tạo vì cả hai đều duy trì trạng thái thực thi trong suốt quá trình tạm ngưng. Sự khác biệt là giao thức và mục đích.
Trình tạo mang lại giá trị cho người tiêu dùng vòng lặp.
Một coroutine chờ các hoạt động không đồng bộ khác và cuối cùng trả về một kết quả cuối cùng.python id="o2u8bi" async def fetch(): data = await read() return data Đang gọifetch()không chạy cơ thể để hoàn thành. Nó tạo ra một đối tượng coroutine.```python id="9i5ai1"
coro = fetch()
## 36.1 Hàm Coroutine vs Đối tượng Coroutine
Một`async def`câu lệnh tạo ra một hàm coroutine.
Việc gọi hàm coroutine sẽ tạo ra một đối tượng coroutine.```python id="rt8ky9"
async def work():
return 42
coro = work()
```Về mặt khái niệm:```text id="q71j65"
work
coroutine function object
work()
coroutine object
suspended execution state
code object
frame or frame-like state
```Điều này khác với một chức năng thông thường:```python id="nv1t8j"
def work():
return 42
work()
```Một lệnh gọi hàm thông thường sẽ chạy ngay lập tức và trả về`42`.
Lệnh gọi hàm không đồng bộ trả về một đối tượng coroutine mà sau này phải được điều khiển.
## 36,2`await`
`await`tạm dừng coroutine hiện tại cho đến khi một coroutine khác có thể chờ đợi hoàn tất.```python id="wjue72"
async def outer():
value = await inner()
return value + 1
```Biểu thức:```python id="pbwts5"
await inner()
```thực hiện một số điều về mặt khái niệm:```text id="n2ycfi"
call inner()
obtain awaitable object
suspend current coroutine
let event loop drive awaitable
resume current coroutine with result
```Nếu hoạt động được chờ đợi tăng lên, ngoại lệ sẽ được đưa trở lại vào coroutine đang chờ.```python id="yc56f3"
async def outer():
try:
value = await inner()
except ValueError:
value = 0
return value
```## 36.3 Đang chờ`await`hoạt động trên các đối tượng được chờ đợi.
Những thứ được chờ đợi phổ biến bao gồm:```text id="o2vwvk"
coroutine objects
asyncio Task objects
asyncio Future objects
objects implementing __await__
```Một đối tượng tùy chỉnh có thể được chờ đợi bằng cách xác định`__await__`.
```python id="f4sd9q"
class Immediate:
def __await__(self):
yield
return 42
```Trong thực tế, hầu hết mã ứng dụng đều chờ coroutine, nhiệm vụ và tương lai được tạo bởi khung không đồng bộ.
## 36.4 Trạng thái coroutine
Một coroutine có thể ở các trạng thái tương tự như trạng thái của trình tạo:```text id="qcur3i"
created
running
suspended
closed
```Sử dụng`inspect`:
```python id="84zov8"
import inspect
async def work():
await other()
coro = work()
print(inspect.getcoroutinestate(coro))
```Các trạng thái phổ biến bao gồm:```text id="h0yb3u"
CORO_CREATED
CORO_RUNNING
CORO_SUSPENDED
CORO_CLOSED
```Nhiều người tiêu dùng không thể chờ đợi một coroutine cùng một lúc. Nó đại diện cho một lần thực hiện.
## 36.5 Khung Coroutine
Một coroutine bị đình chỉ sẽ giữ trạng thái thực thi của nó.
Trạng thái đó bao gồm:```text id="o61wj7"
code object
instruction position
local variables
value stack
exception state
currently awaited object
running state
closed state
```Ví dụ:```python id="1tow3u"
async def process():
data = await read()
return transform(data)
```Trong khi bị đình chỉ tại`await read()`, coroutine phải nhớ:```text id="985lzm"
current frame
local variables
await target
next instruction after await
```Khi`read()`hoàn tất, coroutine sẽ tiếp tục và gán giá trị trả về cho`data`.
## 36.6 Coroutine sử dụng cùng một Frame Model
Coroutine không sử dụng trình thông dịch riêng. Chúng được thực thi bởi cùng một vòng đánh giá CPython.
Vòng lặp chạy cho đến coroutine:```text id="p7w1wv"
awaits and suspends
returns
raises
is cancelled
```Về mặt khái niệm:```text id="xzr16h"
coroutine object
frame state
bytecode
stack
locals
event loop
resumes coroutine
evaluation loop runs frame
stops at await or completion
```Vòng lặp sự kiện thực hiện lập lịch trình. CPython cung cấp bộ máy thực thi có thể tiếp tục.
## 36.7 Vòng lặp sự kiện
Vòng lặp sự kiện điều phối các tác vụ không đồng bộ.
TRONG`asyncio`, vòng lặp sự kiện quản lý:```text id="n7xdfh"
ready tasks
sleep timers
socket readiness
future completion
callbacks
cancellation
exception reporting
```Ví dụ:```python id="0chlb7"
import asyncio
async def main():
await asyncio.sleep(1)
return 42
result = asyncio.run(main())
print(result)
asyncio.runtạo và điều khiển một vòng lặp sự kiện cho đến khimain()hoàn thành.
Bản thân CPython cung cấp các đối tượng coroutine vàawaitngữ nghĩa.asynciocung cấp một triển khai vòng lặp sự kiện tiêu chuẩn.
36.8 Nhiệm vụ
Riêng đối tượng coroutine là thụ động. Một tác vụ lên lịch cho nó thực hiện.```python id="8et1tq" import asyncio
async def work(): await asyncio.sleep(1) return 42
async def main():
task = asyncio.create_task(work())
result = await task
return result
Về mặt khái niệm:text id="p93t67"
coroutine object
passive resumable computation
task event-loop managed wrapper resumes coroutine stores result or exception supports cancellation
## 36.9 Hợp tác đồng thời
Async Python sử dụng đồng thời hợp tác.
Một coroutine chạy cho đến khi đạt đến điểm chờ.```python id="8ux1ur"
async def work():
step1()
await wait()
step2()
```Trong lúc`step1()`, không có tác vụ nào khác chạy trên vòng lặp sự kiện đó trừ khi`step1()`chính nó đang chờ hoặc trả lại quyền điều khiển.
Tại`await wait()`, coroutine tạm dừng và vòng lặp sự kiện có thể chạy một tác vụ khác.
Điều này có nghĩa là mã nặng CPU bên trong coroutine có thể chặn vòng lặp sự kiện:```python id="g8fwp9"
async def bad():
while True:
compute()
```Không có`await`, coroutine này không mang lại quyền kiểm soát.
## 36.10 Async không phải là tính song song
Đồng thời không đồng bộ không tự động có nghĩa là song song CPU.
Một vòng lặp sự kiện thường chạy trong một luồng hệ điều hành. Nó chỉ chuyển đổi giữa các nhiệm vụ tại các điểm treo.
Async hoạt động tốt cho:```text id="oell4m"
network I/O
many open connections
timeouts
sleeping
waiting for subprocesses
streaming protocols
cooperative task orchestration
```Nó không làm cho mã byte Python gắn với CPU chạy song song.
Đối với công việc liên quan đến CPU, hãy sử dụng:```text id="r5575k"
native extensions
multiprocessing
process pools
thread pools for blocking calls
free-threaded builds where appropriate
external workers
```## 36.11 Đang chờ Coroutine
Cho:```python id="h5auqh"
async def inner():
return 10
async def outer():
x = await inner()
return x + 1
```Dòng chảy là:```text id="fi924o"
outer starts
outer calls inner(), producing inner coroutine
outer awaits inner coroutine
event loop drives inner
inner returns 10
outer resumes with x = 10
outer returns 11
```Giá trị trả về vượt qua ranh giới chờ đợi trở lại khung bị treo.
##36.12 Chờ đợi một tương lai
Tương lai đại diện cho một kết quả có thể chưa tồn tại.```python id="6xf2w8"
future = loop.create_future()
```Một coroutine có thể chờ đợi nó:```python id="qze0h0"
value = await future
```Nếu tương lai chưa hoàn tất, coroutine sẽ tạm dừng.
Sau đó:```python id="nrkg2x"
future.set_result(42)
```Vòng lặp sự kiện đánh dấu các nhiệm vụ đang chờ sẵn sàng. Coroutine đang chờ tiếp tục với`42`.
Nếu tương lai có ngoại lệ:```python id="xzr05h"
future.set_exception(ValueError("bad"))
```coroutine đang chờ sẽ tiếp tục bằng cách đưa ra ngoại lệ đó tại điểm chờ.
## 36.13 Đang chờ nhiệm vụ
Một nhiệm vụ cũng được chờ đợi.```python id="w7s6x8"
task = asyncio.create_task(work())
result = await task
```Nếu nhiệm vụ kết thúc bình thường,`await task`trả về kết quả của nó.
Nếu nhiệm vụ tăng lên,`await task`đưa ra ngoại lệ tương tự.
Nếu nhiệm vụ bị hủy bỏ,`await task`tăng lên`CancelledError`.
## 36.14 Hủy bỏ
Việc hủy yêu cầu một tác vụ phải dừng lại.```python id="j5ce0q"
task.cancel()
```TRONG`asyncio`, việc hủy bỏ được thực hiện bằng cách tiêm`CancelledError`vào coroutine tại một điểm chờ.```python id="lczbrw"
async def work():
try:
await asyncio.sleep(10)
except asyncio.CancelledError:
cleanup()
raise
```Một coroutine có thể bắt được lệnh hủy để dọn dẹp, nhưng nó thường phải khởi động lại trừ khi nó cố ý ngăn chặn việc hủy.
Việc hủy bỏ là hợp tác. Một coroutine không bao giờ chờ đợi có thể không quan sát thấy việc hủy kịp thời.
## 36.15 Dọn dẹp bằng`try/finally`Sử dụng`try/finally`để dọn dẹp không đồng bộ.```python id="j83mx6"
async def work():
resource = await acquire()
try:
await use(resource)
finally:
await release(resource)
```các`finally`khối chạy trên:```text id="m2ocv7"
normal completion
exception
cancellation
```Nếu quá trình dọn dẹp đang chờ xử lý thì coroutine có thể tạm dừng trong quá trình dọn dẹp.
Điều này làm cho việc hủy bỏ và dọn dẹp trở nên tinh tế. Coroutine có thể ở trạng thái bị hủy trong khi vẫn thực thi mã quyết toán.
## 36.16 Trình quản lý bối cảnh không đồng bộ
Trình quản lý bối cảnh không đồng bộ sử dụng`async with`.
```python id="v2e2wy"
async with lock:
await work()
```Đối tượng phải cung cấp:```text id="5scc5n"
__aenter__
__aexit__
```Về mặt khái niệm:```python id="dkm7oc"
mgr = lock
value = await mgr.__aenter__()
try:
await work()
except BaseException as exc:
suppress = await mgr.__aexit__(type(exc), exc, exc.__traceback__)
if not suppress:
raise
else:
await mgr.__aexit__(None, None, None)
```Trình quản lý bối cảnh không đồng bộ cho phép tạm dừng thu thập và phát hành tài nguyên.
## 36.17 Trình lặp không đồng bộ
Sử dụng lặp lại không đồng bộ`async for`.
```python id="hvh27p"
async for item in stream:
process(item)
```Đối tượng phải cung cấp:```text id="u37g80"
__aiter__
__anext__
```Về mặt khái niệm:```python id="z1gd9g"
ait = stream.__aiter__()
while True:
try:
item = await ait.__anext__()
except StopAsyncIteration:
break
process(item)
```Lặp lại không đồng bộ rất hữu ích cho các luồng trong đó mỗi mục tiếp theo có thể yêu cầu I/O.
## 36.18 Trình tạo không đồng bộ
Trình tạo không đồng bộ được xác định bằng`async def`Và`yield`.
```python id="65vpyy"
async def lines(reader):
async for line in reader:
yield line.strip()
```Nó tạo ra một trình vòng lặp không đồng bộ.
Sử dụng:```python id="5lhj9g"
async for line in lines(reader):
print(line)
```Trình tạo Async có thể vừa chờ vừa mang lại kết quả.```python id="8c9u5e"
async def gen():
await asyncio.sleep(1)
yield 1
```Họ kết hợp hệ thống treo coroutine với việc tạo ra giá trị theo kiểu máy phát điện.
## 36,19`anext`
`anext`lấy mục tiếp theo từ một trình vòng lặp không đồng bộ.```python id="vs0dl0"
item = await anext(ait)
```Điều này đang chờ đợi`ait.__anext__()`.
Nếu trình lặp async đã hết, nó sẽ tăng`StopAsyncIteration`.
Một mặc định có thể được cung cấp:```python id="8d97ug"
item = await anext(ait, default)
```## 36,20`StopAsyncIteration`Hoàn thành tín hiệu của trình vòng lặp không đồng bộ với`StopAsyncIteration`.
Điều này khác biệt với`StopIteration`.
```text id="prf78x"
normal iterator ends with StopIteration
async iterator ends with StopAsyncIteration
async forđánh bắtStopAsyncIterationđể thoát khỏi vòng lặp.
Nâng caoStopIterationtừ lần lặp không đồng bộ là không chính xác.
36.21 Mã byte Coroutine
Hàm async biên dịch thành một đối tượng mã được đánh dấu là mã coroutine.```python id="m36blp" async def f(): return 1
Một chức năng không đồng bộ với đang chờ:```python id="vb752s"
async def f():
value = await g()
return value
```về mặt khái niệm bao gồm mã byte cho:```text id="aw12fn"
call g
get awaitable iterator
send into awaitable
suspend if not done
resume with result
store value
return value
```Mã byte chính xác thay đổi theo phiên bản Python. Mô hình vẫn còn:`await`được triển khai dưới dạng thực thi khung có thể tiếp tục.
## 36,22`SEND`và chờ đợi
Mã byte CPython hiện đại sử dụng máy móc giống như gửi để điều khiển các sản phẩm đang chờ.
Về mặt khái niệm:```text id="c07p30"
await awaitable:
get awaitable iterator
send None or value
if it yields:
suspend current coroutine
if it returns:
resume with result
if it raises:
propagate exception
```Điều này liên quan đến ủy quyền của máy phát điện. Coroutine được xây dựng dựa trên ý tưởng tương tự là gửi giá trị vào các phép tính bị treo.
## 36.23 Trả về Coroutine
Một coroutine trả về một giá trị cuối cùng.```python id="11vkrn"
async def f():
return 42
```Khi chờ đợi:```python id="q0irxd"
value = await f()
```coroutine đang chờ nhận được`42`.
Trong nội bộ, sự hoàn thành được thể hiện thông qua giao thức có thể chờ đợi. Ở cấp độ người dùng,`await`biến việc hoàn thành coroutine thành một kết quả biểu thức thông thường.
## 36.24 Ngoại lệ của Coroutine
Nếu một coroutine tăng lên, hãy chờ nó tăng lên.```python id="ufon8f"
async def f():
raise ValueError("bad")
async def main():
await f()
```Ngoại lệ lan truyền đến`main`tại điểm chờ.
Bạn có thể bắt nó:```python id="vi414s"
async def main():
try:
await f()
except ValueError:
return 0
```Truy nguyên bao gồm các khung coroutine liên quan đến chuỗi cuộc gọi không đồng bộ.
## 36.25 Cảnh báo về Coroutine
Việc tạo một coroutine và không bao giờ chờ đợi nó thường là một lỗi.```python id="j9rvzc"
async def f():
return 1
f()
```Điều này tạo ra một đối tượng coroutine và loại bỏ nó.
Python có thể cảnh báo:```text id="e1rugz"
RuntimeWarning: coroutine was never awaited
```Cơ thể không bao giờ chạy.
Cách sử dụng đúng:```python id="5e8f4p"
await f()
```hoặc:```python id="daxsm1"
asyncio.create_task(f())
```## 36,26`asyncio.run`
`asyncio.run`là điểm vào tiêu chuẩn để chạy chức năng chính không đồng bộ.```python id="45lxp3"
import asyncio
async def main():
await asyncio.sleep(1)
return 42
print(asyncio.run(main()))
```Nó tạo một vòng lặp sự kiện, chạy coroutine cho đến khi hoàn thành, xử lý việc dọn dẹp trình tạo async cuối cùng và đóng vòng lặp.
Bạn thường gọi nó một lần ở cấp cao nhất của chương trình.
## 36.27 Chặn cuộc gọi bên trong mã Async
Chặn cuộc gọi sẽ dừng vòng lặp sự kiện.
Xấu:```python id="upggpj"
import time
async def main():
time.sleep(5)
```Trong lúc`time.sleep`, vòng lặp sự kiện không thể chạy các tác vụ khác.
Tốt hơn:```python id="j76gyt"
import asyncio
async def main():
await asyncio.sleep(5)
```Đối với các chức năng chặn không thể thực hiện không đồng bộ, hãy sử dụng trình thực thi hoặc trình trợ giúp luồng:```python id="bo70ck"
result = await asyncio.to_thread(blocking_function, arg)
```Điều này giữ cho vòng lặp sự kiện phản hồi nhanh.
## 36.28 Nhóm nhiệm vụ
Các nhiệm vụ liên quan đến nhóm đồng thời có cấu trúc.```python id="jrw68m"
import asyncio
async def main():
async with asyncio.TaskGroup() as tg:
tg.create_task(fetch_one())
tg.create_task(fetch_two())
```Một nhóm nhiệm vụ chờ đợi các nhiệm vụ con của nó. Nếu một nhiệm vụ thất bại, nhóm sẽ điều phối việc hủy bỏ và đưa ra các ngoại lệ được nhóm nếu cần.
Điều này an toàn hơn việc tạo nhiệm vụ mà không theo dõi chúng.
## 36,29 Nhóm ngoại lệ trong mã Async
Nhiệm vụ đồng thời có thể thất bại cùng nhau.
Nhóm tác vụ có thể báo cáo nhiều lỗi bằng cách sử dụng các nhóm ngoại lệ.```python id="75j6zk"
try:
async with asyncio.TaskGroup() as tg:
tg.create_task(a())
tg.create_task(b())
except* ValueError as group:
handle_value_errors(group)
except*có thể phân chia các ngoại lệ được nhóm theo loại.
Điều này rất quan trọng đối với các hệ thống không đồng bộ vì các tác vụ độc lập có thể bị lỗi trong cùng một hoạt động có cấu trúc.
36.30 Trình tạo và dọn dẹp không đồng bộ
Trình tạo không đồng bộ cần dọn dẹp không đồng bộ.python id="6lt8y0" async def gen(): try: yield 1 finally: await cleanup() Nếu trình tạo async chưa cạn kiệt, nó sẽ được đóng lại bằngaclose().
agen = gen()
item = await anext(agen)
await agen.aclose()
```Vòng lặp sự kiện cũng bao gồm máy móc để hoàn thiện các trình tạo không đồng bộ đang chờ xử lý trong khi tắt máy.
## 36.31 Phương thức tạo Async
Trình tạo Async hỗ trợ các phương thức tương tự như trình tạo nhưng có thể chờ đợi:
| Phương pháp | Ý nghĩa |
|---|---|
|`__anext__()`| Nhận mục tiếp theo không đồng bộ |
|`asend(value)`| Gửi giá trị vào trình tạo async |
|`athrow(exc)`| Ném ngoại lệ vào trình tạo async |
|`aclose()`| Đóng trình tạo không đồng bộ |
Những phương thức này trả về những thứ có thể chờ đợi.
Ví dụ:```python id="iuoltd"
value = await agen.__anext__()
await agen.aclose()
```## 36.32 Coroutine và thời gian tham chiếu
Một coroutine bị đình chỉ sẽ giữ cho các biến cục bộ tồn tại.```python id="3yoa52"
async def work():
data = bytearray(100_000_000)
await asyncio.sleep(10)
return len(data)
```Trong khi ngủ,`data`vẫn còn sống vì coroutine có thể tiếp tục và sử dụng nó.
Chuỗi lưu giữ:```text id="fhhddc"
task
coroutine
suspended frame
local data
```Xóa các địa phương lớn trước khi chờ đợi lâu khi có thể:```python id="7hxthq"
async def work():
data = bytearray(100_000_000)
result = process(data)
data = None
await asyncio.sleep(10)
return result
```## 36.33 Thời gian thực hiện nhiệm vụ
Một nhiệm vụ giữ cho coroutine của nó tồn tại.```python id="4ffgq1"
task = asyncio.create_task(work())
```Cho đến khi tác vụ hoàn thành hoặc bị hủy và hoàn tất, tác vụ sẽ tham chiếu coroutine và trạng thái khung của nó.
Nếu bạn tạo nhiệm vụ và mất dấu chúng, các ngoại lệ có thể được ghi lại sau đó và tài nguyên có thể vẫn hoạt động lâu hơn dự kiến.
Các mẫu có cấu trúc như nhóm nhiệm vụ giúp kiểm soát thời gian sống.
## 36,34 Dấu vết ngăn xếp không đồng bộ
Dấu vết ngăn xếp không đồng bộ bao gồm các chuỗi coroutine bị treo.
Khi một ngoại lệ đi qua`await`ranh giới, truy nguyên cho biết nơi nó được nâng lên và nơi nó được chờ đợi.
Ví dụ:```python id="uyj5ih"
async def a():
await b()
async def b():
await c()
async def c():
1 / 0
```Truy nguyên có thể hiển thị chuỗi không đồng bộ từ`a`ĐẾN`b`ĐẾN`c`.
Điều này có thể thực hiện được vì các khung coroutine bảo toàn thông tin về đối tượng mã và vị trí lệnh.
## 36,35`contextvars`Mã Async thường sử dụng`contextvars`cho trạng thái ngữ cảnh cục bộ.```python id="ulzcon"
from contextvars import ContextVar
request_id = ContextVar("request_id")
async def handle():
print(request_id.get())
```Không giống như lưu trữ cục bộ theo luồng, các biến ngữ cảnh được thiết kế để hoạt động chính xác trên các chuyển đổi tác vụ không đồng bộ.
Mỗi nhiệm vụ có thể mang bối cảnh riêng của nó.
Điều này rất quan trọng đối với:```text id="ucdnv4"
request IDs
tracing
logging context
database transaction context
auth state
locale settings
```## 36.36 Async và GIL
Mã Async không xóa GIL.
Trong CPython truyền thống:```text id="vow7l4"
one thread executes Python bytecode at a time per interpreter
async tasks switch cooperatively at await points
```Mã không đồng bộ có thể xử lý nhiều tác vụ liên quan đến I/O một cách hiệu quả vì phần lớn thời gian được dành để chờ đợi các sự kiện bên ngoài.
Nó không làm cho các vòng lặp Python nặng về CPU thực thi song song.
## 36,37 Không đồng bộ so với Chủ đề
Async và chủ đề giải quyết các vấn đề khác nhau.
| Tính năng | Nhiệm vụ không đồng bộ | Chủ đề |
|---|---|---|
| Lập kế hoạch | Hợp tác xã | Kiểm tra trước bởi hệ điều hành và trình thông dịch |
| Chuyển đổi điểm |`await`| Lập kế hoạch chủ đề và chuyển giao GIL |
| Tốt nhất cho | Nhiều tác vụ I/O | Chặn API, tích hợp mã đồng bộ |
| Bộ nhớ dùng chung | Cùng một chủ đề thường | Được chia sẻ qua các chủ đề |
| Rủi ro cuộc đua | Thấp hơn nhưng vẫn có thể | Cao hơn |
| Sự song song của CPU trong CPython truyền thống | Không | Bị giới hạn bởi GIL đối với mã byte Python |
Mã Async nêu rõ ràng về việc tạm ngưng. Chủ đề có thể chuyển đổi ở những điểm ít rõ ràng hơn.
## 36,38 Async so với Trình tạo
Coroutine và trình tạo chia sẻ khả năng thực thi có thể tiếp tục nhưng các giao thức thì khác nhau.
| Tính năng | Máy phát điện | Coroutine |
|---|---|---|
| Định nghĩa |`def`với`yield` | `async def`|
| Sản xuất | Nhiều giá trị mang lại | Một kết quả cuối cùng |
| Người tiêu dùng |`for`, `next`, `send` | `await`, vòng lặp sự kiện |
| Hoàn thành |`StopIteration`| Chờ kết quả hoặc ngoại lệ |
| Công dụng chính | Lặp lại lười biếng | Phối hợp I/O không đồng bộ |
| Có thể chờ đợi | Không | Có |
| Có thể mang lại giá trị đơn giản | Có | Không, ngoại trừ trình tạo không đồng bộ |
Một coroutine không phải là một trình vòng lặp. Máy phát điện không thể chờ đợi trực tiếp trừ khi được điều chỉnh.
## 36.39 Trình lập lịch Coroutine tối thiểu
Một bộ lập lịch đồ chơi có thể thể hiện ý tưởng cốt lõi.```python id="zytwib"
from collections import deque
class Sleep:
def __await__(self):
yield self
return None
async def task(name):
print(name, "start")
await Sleep()
print(name, "end")
def run(coros):
ready = deque(c.__await__() for c in coros)
while ready:
aw = ready.popleft()
try:
next(aw)
except StopIteration:
continue
ready.append(aw)
run([task("a"), task("b")])
```Đây không phải là`asyncio`. Nó bỏ qua I/O thực, bộ tính giờ, tương lai, hủy, ngoại lệ và trạng thái tác vụ. Nhưng nó cho thấy cơ chế chính:```text id="6z9pem"
coroutine runs
await yields control
scheduler later resumes it
```## 36.40 Những hiểu lầm phổ biến
| Hiểu lầm | Đúng mẫu |
|---|---|
| Gọi một hàm không đồng bộ sẽ chạy nó | Nó tạo ra một đối tượng coroutine |
|`await`bắt đầu một chủ đề mới | Nó tạm dừng coroutine hiện tại cho đến khi chờ đợi hoàn tất |
| Async làm cho mã CPU song song | Nó chủ yếu giúp hợp tác đồng thời I/O |
| Một coroutine có thể được chờ đợi nhiều lần | Một đối tượng coroutine đại diện cho một lần thực thi |
|`asyncio.create_task`cũng giống như`await`| Nó lên lịch đồng thời;`await`chờ hoàn thành |
| Chặn cuộc gọi vẫn ổn trong mã async | Họ chặn vòng lặp sự kiện |
| Hủy bỏ mã ngay lập tức | Nó hợp tác tiêm một ngoại lệ |
| Async sử dụng trình thông dịch khác | Nó sử dụng khung CPython và vòng đánh giá |
## 36.41 Chiến lược đọc
Bắt đầu với:```python id="bltl80"
async def f():
return 1
```Sau đó:```python id="zf4zrn"
async def g():
value = await f()
return value + 1
```Thanh tra:```python id="60r9ah"
import dis
import inspect
print(inspect.iscoroutinefunction(f))
coro = f()
print(inspect.getcoroutinestate(coro))
dis.dis(g)
```Sau đó nghiên cứu:```text id="gpxkbm"
await
async with
async for
async generators
tasks
cancellation
TaskGroup
contextvars
blocking calls inside async code
```Đối với mỗi trường hợp, theo dõi:```text id="xhs827"
when the coroutine object is created
when the body starts
where it suspends
what object it awaits
how it resumes
what happens on exception or cancellation
when its frame is cleared
```## 36.42 Tóm tắt chương
Coroutine là các phép tính có thể tiếp tục được sử dụng cho lập trình không đồng bộ. MỘT`async def`cuộc gọi tạo ra một đối tượng coroutine. Nội dung coroutine chỉ chạy khi được chờ đợi hoặc được lên lịch. Tại mỗi`await`, coroutine có thể tạm dừng, giữ nguyên trạng thái khung và sau đó tiếp tục với một giá trị hoặc ngoại lệ.
Mô hình cốt lõi là:```text id="r29f1z"
async function call
↓
create coroutine object
↓
event loop or await resumes coroutine
↓
run until await, return, raise, or cancellation
↓
await suspends and yields control
↓
resume later with result or exception
```Việc thực thi không đồng bộ được xây dựng trên nền tảng CPython giống như thực thi thông thường: đối tượng mã, khung, mã byte, ngoại lệ và giao thức đối tượng. Vòng lặp sự kiện cung cấp lịch trình; CPython cung cấp khả năng thực thi tiếp tục.