摘要
深入讲解异步编程核心语法async/await的实现原理, 阐述async/await的使用场景, 结合实际代码案例对异步IO任务的定义进行演示, 对异步IO任务的调度予以演示, 展示异步IO任务的常见优化方案, 以此帮助开发者快速掌握这一后端开发的核心技术点。
一、异步编程的核心定位
当下, 异步编程属于极为热门的后端技术点当中的一个, 其核心是解决同步IO场景里CPU资源闲置的问题。于网络请求、文件读写、数据库操作等IO密集型场景之中, 同步代码在等待IO返回之际会将整个线程阻塞, CPU利用率通常是不足10%的;况且异步编程借助任务切换机制, 能够在IO等待之时自动去调度其他可执行任务, 于单线程的情况下就能够实现数千的并发连接, 性能对比同步方案提升超过10倍。
3.5正式将async/await语法引入, 与标准库相配合, 早期用生成器模拟异步致使代码可读性欠佳, 调试面临困难复杂状况这两个问题确实被彻底解决了, 5目前已然成为3.0+等主流框架的底层核心技术方面具有影响力的存在。
二、2.1, async/await其基础语法规则里有关异步函数的定义。
借助async def去定义的函数, 被称作协程函数, 对该函数加以调用, 并不会马上执行其中的内部逻辑, 而是会返回一个对象, 此对象需交由事件循环来作出调度以便展开执行。
定义异步函数
async def (url: str) -> str:
print(f"开始请求{url}")
模拟IO等待,await只能在async函数内使用
await .sleep(2) # 此处替换为实际网络请求
print(f"请求{url}完成")
f"{url}的响应数据"
留意, 平常的同步函数内部不可以直接运用await关键字, 不然的话就会抛出语法方面的错误。
2.2 事件循环的使用
事件循环作为异步任务的调度核心, 承担着管理所有协程执行、暂停以及唤醒的职责, 3.7 及以上版本提供了高层的.run(), 能够快速启动此事件循环。
async def main():
单个协程执行
= await ("url")
print()
if == "":
.run(main())
执行上面所提到的代码之时, 将会看到这样的情况: 首先打印出"开始请求url", 在等待2秒钟之后, 打印出请求完成以及返回的结果, 整个执行的逻辑跟同步代码相类似, 不过在IO等待的时候, 线程能够去处理其他的任务。
三、并发任务的调度实现
异步编程的关键价值在于同时去并发执行多个 IO 任务, , ()会是那种最常被运用的并发调度接口, 它能够在同一时刻去运行多个协程, 并且还能收集所有的返回结果:
async def ():
urls =
"url/1",
"url/2",
"url/3"

并发执行3个请求,总耗时约2秒而非6秒
tasks =
(url) for url in urls
= await .(*tasks)
for res in :
print(res)
if == "":
.run(())
将上述代码予以执行, 可以目睹三个请求的日志之中, "开始请求"的那部分几乎是在同一时刻进行打印, 两秒过后, 完成日志同时被打印出来, 总体所耗费的时间仅仅等同于单个请求所消耗的时间, 性能方面的提升极为显著。
要是针对单个任务的生命周期, 想要开展更为精准细致的把控, 诸如对任务予以取消操作、设定超时情况等, 那么能够借助.()这种方式, 从而把协程包装成Task对象:
async def ():
task = .(("url"))
try:
设置1秒超时,超时后自动取消任务
= await .(task, =1)
print()
.:
print("请求超时,已取消任务")
print(f"任务是否被取消:{task.()}")
四、使用异步编程的注意事项
-
要防止同步阻塞代码出现, 在异步函数里头, 要是运用time.sleep()、同步请求、同步文件读写这类阻塞操作, 就会致使整个事件循环停滞, 所有异步任务都会暂停下来。与之相对应的解决办法是采用异步版本的库, 像进行替代, 去替代内置open函数。
-
不适用CPU密集型场景, 异步编程仅对IO等待的闲置时间起到优化作用。倘若业务逻辑涵盖大量计算内容, 由于任务切换, 单线程的异步模型反倒会增添开销。在这种情形下, 应当采用多进程方案并同步配合异步IO来使用。
-
存在这样一种异常处理规则, 即默认情况下, 只要有一个任务抛出异常, 那么所涉及的所有任务都会被终止, 并且会抛出异常。要是有需求让任务能够独立失败, 那么可以将某个参数设置为真, 这里假设为通过参数设置, 此时异常将会作为返回结果里的一部分内容, 面对这种情况, 使用者需要自己去进行判断以及处理。
总结
async/await身为异步编程的关键语法, 是当前后端开发涵盖的, 爬虫开发涉及的, 微服务架构必备的技术要点。开发者只要依照"IO操作异步化、同步阻塞避免化"的准则, 便能在不增添硬件成本的状况下大幅提高服务并发能力。搭配等现代异步框架, 还能够大幅削减接口响应延迟, 是开发者2024年务必掌握的核心技能之一。