asyncio高性能的关键在于I/O真非阻塞、事件循环不被阻塞、协程真正并发;time.sleep()会阻塞整个事件循环,应改用await asyncio.sleep();调用同步库需用to_thread或run_in_executor;gather适合统一等待,create_task适合独立控制任务。

asyncio 不是“开了协程就自动高性能”,关键在 I/O 调度是否真非阻塞、事件循环是否被意外阻塞、以及协程是否真正并发执行。
为什么 time.sleep() 会让 asyncio 协程卡住?
这是最常踩的坑:time.sleep() 是同步阻塞调用,会直接挂起整个事件循环。即使它写在 async def 函数里,也不会变成异步行为。
- ✅ 正确做法:用
await asyncio.sleep(1)—— 它把控制权交还给事件循环,允许其他协程运行 - ❌ 错误写法:
time.sleep(1)或os.system("sleep 1"),它们会冻结整个程序 - 注意:
asyncio.sleep()的参数单位是秒(浮点数),不是毫秒;它底层基于loop.call_later(),不占用 CPU
如何安全地调用第三方同步库(比如 requests)?
requests、sqlite3、pandas 等默认都是同步阻塞库,直接 await 会报错,强行在协程里调用则拖垮性能。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- ✅ 推荐方案:用
asyncio.to_thread()(Python 3.9+)包装,例如:await asyncio.to_thread(requests.get, "https://httpbin.org/delay/2") - ⚠️ 兼容旧版:用
loop.run_in_executor(None, requests.get, url),但需显式获取 loop(asyncio.get_running_loop()) - ❌ 别用
asyncio.create_task()包裹同步函数——这不会让它变异步,只是换个线程跑,仍可能阻塞
asyncio.gather() 和 asyncio.create_task() 该怎么选?
两者都用于并发,但调度时机和错误传播机制完全不同,选错会导致超时、异常丢失或资源泄漏。
-
asyncio.gather():适合“等全部完成”,支持return_exceptions=True收集所有异常;但任一任务失败,默认立刻取消其余任务 -
asyncio.create_task():更底层,任务立即被调度,适合需要独立生命周期控制的场景(比如后台心跳、长连接保活) - ⚠️ 关键区别:用
gather()时,如果某个协程耗时远超预期,你无法单独 cancel 它;而create_task()可以随时task.cancel() - 示例:并发发 10 个 HTTP 请求,用
gather()更简洁;但若其中某请求要设单独超时,就得用create_task()+asyncio.wait_for()
真正的瓶颈往往不在协程语法本身,而在你是否检查过每个 await 表达式背后是不是真异步、有没有隐式同步调用混入、以及连接池/限流策略是否匹配目标服务的吞吐能力。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










