下载工作台
Python 编程实战

协程与 asyncio

试读上半部分 · 解锁后可读全文

第 14 章 · 协程与 asyncio

本章目标:理解 协程async/await 语义;使用 asyncio 运行与调度协程;掌握 create_task / gather / wait_for;对比 线程 / 进程 / 协程 选型;能编写 高并发 I/O 脚本(并发 HTTP、异步读写);了解 aiohttp 与同步 requests 的差异。

学时建议:4~5 小时(含 2 小时 async 实验)

前置ch12 多线程;ch13 多进程;ch11 requestsch05 函数。


14.1 协程是什么

协程(coroutine) 是可暂停、可恢复的函数;遇到 I/O 等待时让出控制权,事件循环去跑别的协程。

线程:OS 调度,抢占式,有栈
协程:事件循环调度,协作式,单线程内切换
对比线程 (ch12)协程 (本章)
调度OSasyncio 事件循环
内存每线程 ~MB 栈轻量,大量连接
适用一般 I/O海量 I/O(爬虫、网关)
CPU 密集受 GIL 限仍受 GIL,应放进程池

shop-demo 场景:同时检查 200 个商品 URL 是否 200 OK——协程比 200 线程更省资源。


14.2 第一个 async 程序

import asyncio


async def fetch_name(sku: str) -> str:
    await asyncio.sleep(0.5)   # 模拟 I/O,不阻塞整个进程
    return f"product-{sku}"


async def main() -> None:
    result = await fetch_name("BK-001")
    print(result)


if __name__ == "__main__":
    asyncio.run(main())
关键字含义
async def定义协程函数
await等待可等待对象,期间可切换
asyncio.run(main())创建事件循环并运行顶层协程
规则await 只能在 async def 内使用;协程必须被 await 或交给事件循环,否则只得到 coroutine 对象。

14.3 并发:create_task 与 gather

串行(慢):

async def main():
    a = await fetch_name("A")
    b = await fetch_name("B")

并发(快):

async def main() -> None:
    t1 = asyncio.create_task(fetch_name("A"))
    t2 = asyncio.create_task(fetch_name("B"))
    print(await t1, await t2)


# 或一次性等待多个
async def main_gather() -> None:
    results = await asyncio.gather(
        fetch_name("A"),
        fetch_name("B"),
        fetch_name("C"),
    )
    print(results)
API说明
create_task(coro)排入循环,立即返回 Task
asyncio.gather(*aws)并发等待,结果顺序与传入一致
return_exceptions=True某个失败不拖垮全部

14.4 超时与取消:wait_for

async def slow():
    await asyncio.sleep(10)


async def main():
    try:
        await asyncio.wait_for(slow(), timeout=2.0)
    except asyncio.TimeoutError:
        print("timeout")

生产环境对外部 HTTP 必须设 timeout(与 ch11 requests 同理)。


14.5 实战:并发探测 URL

使用标准库 asyncio + 线程池跑阻塞 I/O(无需额外安装):

import asyncio
import urllib.request

URLS = [
    "https://httpbin.org/get",
    "https://httpbin.org/delay/1",
    "https://httpbin.org/status/404",
]


def blocking_fetch(url: str) -> tuple[str, int]:

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。