Python异步编程详解_asyncio协程实现与性能优化

asyncio协程是单线程内基于事件循环的并发机制,适用于I/O密集型任务,需用await或asyncio.run()执行,避免阻塞事件循环。

asyncio协程不是多线程,也不是多进程

协程是单线程内的并发调度机制,靠事件循环(event loop)控制多个协程的挂起与恢复。它不创建新线程或进程,因此没有线程切换开销,也不涉及锁竞争。适合 I/O 密集型任务,比如网络请求、文件读写、数据库查询等。CPU 密集型任务用协程反而可能因阻塞事件循环而降低性能。

async/await 是协程的语法糖,不是魔法

定义协程函数只需在 def 前加 async,调用时返回一个协程对象,不会立即执行。必须通过 await(在另一个协程内)或 asyncio.run() 才会真正运行。常见误区是把普通函数改成 async 却忘了 await,结果只是生成了个未被调度的对象,什么也没发生。

  • await 只能在 async 函数里用,直接在模块顶层或同步函数中写 await 会报 SyntaxError
  • await 后面必须是可等待对象(Awaitable):协程、Task、Future 或实现了 __await__ 的对象
  • return 和 yield 不能共存于同一个 async 函数中,async generator 要用 async def ... yield

合理使用 Task 和 create_task 提升并发粒度

直接 await coro 是顺序执行;想真正并发,得用 asyncio.create_task(coro) 把协程包装成 Task 并立即调度。Task 是 asyncio 中的“轻量级并发单元”,比直接 await 更灵活——可以取消、检查状态、设置回调。

  • 多个 IO 请求不要串着 await,改用 await asyncio.gather(t1, t2, t3) 或先 create_taskawait 对应 Task
  • 长时间运行的协程建议定期 await asyncio.sleep(0) 让出控制权,避免饿死其他任务
  • 注意 Task 的生命周期:未 await 的 Task 可能被垃圾回收,尤其在函数退出后

性能优化的关键不在“快”,而在“不浪费”

asyncio 的优势不是单次操作更快,而是单位时间内处理更多请求。优化方向集中在减少阻塞、提升吞吐、避免意外同步化。

  • aiohttp 替代 requests,用 aiomysql/asyncpg 替代同步驱动,确保所有 I/O 都真正异步
  • CPU 密集工作(如解析 JSON、加密计算)要丢给 loop.run_in_executor(),防止阻塞事件循环
  • 避免在协程中调用 time.sleep()、print() 过多(虽不阻塞但影响可读性和日志吞吐),调试时可用 logging 配合异步 handler
  • 生产环境开启 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())(Windows)或使用 uvloop(Linux/macOS)替代默认事件循环,可提升 20%~50% 吞吐
协程写起来简单,跑得稳才见功力。关键是理解事件循环怎么调度、哪些操作会偷走它的控制权、以及怎样让每个 await 都物尽其用。