同步(Sync)和异步(Async)的区别
● 同步:是传统的函数调用方式,代码按顺序执行,每一步都必须等待前一步完成。阻塞式执行。
● 异步:使用 async def 定义,可以在等待操作时主动让出控制权,允许其他任务并发执行。
异步编程核心优势:
● 高并发:在I/O等待时切换执行其他任务,充分利用CPU资源。
● 低延迟:避免线程阻塞,适合大量I/O密集型场景(如Web服务、爬虫)。
异步方法的意义就在于让方法在执行过程中如果遇到了需要等待的操作时能够让出控制权,允许其他任务并发。
可通过await或者asyncio.run来执行异步方法
async def my_async_function():
pass

async def main():
result = await my_async_function() # 在异步上下文中

result = asyncio.run(my_async_function()) # 在同步上下文中

这两种调用方法都会导致当前线程阻塞,也就是必须要等待异步方法执行完毕才能继续允许。也就是说异步方法和同步方法的执行都会阻塞调用方的线程,但同步是坏阻塞,异步是好阻塞。同步在阻塞时,
整个线程完全卡住,期间不能做任何其他事,浪费资源。异步在阻塞时,会阻塞当前线程(主线程必须等它结束),但内部的事件循环是并发运行的,异步函数里的 await 会让出执行权,让其他任务同时跑
await 是「异步内部调用工具」,只能在异步函数里用;asyncio.run() 是「异步入口启动器」,只能在同步代码里用。
【注】如果代码里只有一个单独的 async 函数,没有并发任务,那确实 = 和同步一模一样,没有任何区别!
但 ——这不是 asyncio 的错,而是你没用到它的核心能力:并发。
那么什么情况要用async定义异步方法呢?
● 函数里有 await → 必须 async
● 要调用 其他 async 函数 → 必须 async
● 要做 网络 / 数据库 / 文件等等待操作 → 推荐 async
● 纯计算、无等待 → 不要用 async
后端服务开发异步应用
在后端服务中, 天生就是多请求并发,此时的异步就非常有用了
你写的后端(FastAPI、Flask、Django、Sanic 等):
● 不是只跑一个函数就结束
● 而是一直监听端口,等待用户请求
● 同时会有 N 个用户发来请求
所以:后端里绝对不会只跑一个 async 函数 ,就不用担心asyncio.run() 只跑一个函数,和同步一样
在后端服务里:
● 同步框架(Flask 非异步、Django 同步):一个请求卡住,整个线程卡死,并发量极低
● 异步框架(FastAPI、Starlette、Sanic):一个请求 await 等待数据库 / 网络时,立刻去处理其他请求CPU 一刻不闲着,并发能力提升 10~100 倍

那 asyncio.run() 在后端里干嘛?
你在自己写的业务代码里几乎永远不用写!
因为:
● 后端框架已经在底层用 asyncio.run() 启动了事件循环
● 你只需要写 async def 接口 + await 调用数据库 / Redis/HTTP 请求
框架帮你管理了一切并发。

异步框架(FastAPI/Starlette/Sanic):同一时刻确实只跑 1 个线程(单线程)
同步框架(Flask/Django 同步):默认是多线程,但效率低
但 ——单线程的异步框架,性能反而比多线程同步框架强得多!

技术底层原理(极简版)
异步框架 单线程 + 事件循环:

  1. 同一时刻只执行一段代码(确实是单线程跑)
  2. 但遇到 I/O 等待(数据库 / 网络 / Redis),立刻切换去做别的事
  3. 等待结束 → 再切回来继续执行

那么像FastAPI这种单线程的异步框架如何 利用多核 CPU ?
启动多个单线程进程!
● 每个 worker 是独立单线程异步服务
● 4 个 workers 就能跑满 4 核 CPU
这就是生产环境标准用法(多进程+单线程异步)