协程核心在于理解async/await在事件循环中的调度行为,而非课时积累;需避免同步阻塞、正确复用session、区分gather与create_task用途,并厘清执行权归属。
这不是第538讲,也没有所谓“系统学习路线”的固定编号。协程不是靠刷课数积累的,而是靠理解 async/await 在事件循环中的实际行为、调度时机和资源约束。
协程不等于“多线程提速”,它解决的是 I/O 等待期间的 CPU 闲置问题;一旦混入 CPU 密集型操作,asyncio 不但不加速,反而拖慢。
async def 函数返回的是 coroutine 对象,而不是直接执行?因为 Python 的协程是“可暂停、可恢复”的函数对象,必须显式交给事件循环驱动。直接调用 my_coro() 只是创建协程对象,不触发任何逻辑。
await my_coro()(在另一个协程内),或 asyncio.run(my_coro())(顶层入口)my_coro() —— 这会漏掉 RuntimeWarning: coroutine 'xxx' was never awaited,且什么都不会发生type(my_coro()) 确认是 ,不是 None 或结果值asyncio.gather() 和 asyncio.create_task() 的关键区别在哪?前者是并发“批量等待”,后者是立即调度并返回 Task 对象用于后续控制(如取消、检查状态)。
asyncio.gather(a(), b(), c()):等全部完成才返回结果列表,任一异常即中断(除非加 return_exceptions=True)task = asyncio.create_task(a()):立刻把 a() 丢进事件循环队列,当前协程可继续执行其他逻辑,之后再 await task
await asyncio.create_task(...) —— 这等于串行,失去并发意义ai
ohttp 时,为什么连接池没生效?默认情况下,aiohttp.ClientSession() 每次新建都创建独立连接池。复用 session 才能真正复用 TCP 连接和 DNS 缓存。
import aiohttp import asyncio❌ 错误:每次请求都新建 session,连接无法复用
async def bad_request(): async with aiohttp.ClientSession() as session: async with session.get('https://www./link/5f69e19efaba426d62faeab93c308f5c') as resp: return await resp.text()
✅ 正确:session 复用,连接池起作用
async def good_request(session): async with session.get('https://www./link/5f69e19efaba426d62faeab93c308f5c') as resp: return await resp.text()
async def main(): async with aiohttp.ClientSession() as session: await asyncio.gather( good_request(session), good_request(session), good_request(session) )
time.sleep()、json.loads())会怎样?整个事件循环会被阻塞 —— 其他所有协程停摆,直到该同步调用返回。这不是“异步”,是假并发。
loop.run_in_executor() 扔到线程池(注意线程安全)time.sleep):必须换为 await asyncio.sleep()
aiomysql、asyncpg),别硬套 run_in_executor
真正卡住人的从来不是语法,而是没想清楚“谁在等谁”“哪段代码实际占着事件循环”“I/O 完成后回调是否被正确挂起”。协程出问题,90% 是调度逻辑没理清,不是写错了 await。