Python异步编程怎么入门_async await解析-PHP中文网

Python异步编程的核心是 asyncawait,它们不是线程或进程,而是协程(coroutine)的语法糖,用于在单线程中高效处理 I/O 密集型任务(比如网络请求、文件读写、数据库查询)。入门关键不是“多快”,而是理解“什么时候挂起、什么时候恢复”。

async def 定义协程函数,不是普通函数

async def 声明的函数,调用时不会立即执行,而是返回一个协程对象(coroutine object):

async def fetch\_data():

return "done"

coro = fetch\_data() # 这行不运行函数体,只生成协程对象 print(coro) #

要真正运行它,必须交给事件循环(event loop),比如用 await(在协程内部)、asyncio.run()(在顶层)或 loop.run\_until\_complete()(低层)。

await 只能在 async 函数里用,且只能等待“可等待对象”

await 的作用是:暂停当前协程,把控制权交还给事件循环,等被等待的对象准备好(比如 HTTP 响应到达),再恢复执行。它不能用在普通函数里,也不能随意 await 任意东西。

立即学习“Python免费学习笔记(深入)”;

可等待对象包括:

  • 其他协程(由 async def 定义)
  • asyncio.Task(用 asyncio.create\_task() 创建的并发任务)
  • asyncio.Future(底层机制,一般不用手写)

常见错误示例:

\# ❌ 错误:在普通函数里用 await
def bad\_func():

await asyncio.sleep(1)  # SyntaxError

❌ 错误:await 普通函数或数字

async def wrong(): await print("hello") # TypeError: object is not awaitable await 42 # 同样报错

用 asyncio.run() 快速启动事件循环

这是最简单的入门方式——不用手动管理事件循环:

下载

import asyncio

async def main(): print("start") await asyncio.sleep(1) # 模拟耗时 I/O 操作 print("done")

asyncio.run(main()) # 自动创建、运行、关闭事件循环

注意:asyncio.run() 只能调用一次,且必须是程序入口点(不能嵌套调用)。生产环境如 Web 框架(FastAPI、aiohttp)会自己管理事件循环,你只需写 async/await 逻辑。

并发不等于并行:asyncio.gather() 是常用组合技

多个协程可以“看起来同时”运行,实际是事件循环在它们之间快速切换。用 asyncio.gather() 并发执行并收集结果:

async def get\_user(user\_id):

await asyncio.sleep(0.5)  # 模拟 API 请求延迟
return f"user\_{user\_id}"

async def main():

三个请求并发发出,总耗时约 0.5 秒,不是 1.5 秒

results = await asyncio.gather(
    get\_user(1),
    get\_user(2),
    get\_user(3)
)
print(results)  # \['user\_1', 'user\_2', 'user\_3'\]

asyncio.run(main())

对比同步写法:for 循环依次 await,总耗时是各次延迟之和;而 gather 让它们“重叠执行”,显著提升 I/O 密集场景效率。           

已有 2110 条评论

    1. MiaWilson MiaWilson

      I love that you kept this concise. Async can get overwhelming fast but you stuck to the absolute essentials for getting started.

    2. 林嘉豪 林嘉豪

      代码示例里的sleep模拟I/O操作很形象,让我理解异步主要优化的不是CPU计算,而是等待时间。这对写业务代码太重要了。

    3. DanielBrown DanielBrown

      The part about asyncio.run() being the entry point saved me. I was nesting runs and getting weird errors. Now I know why.

    4. 郑思琪 郑思琪

      建议配合asyncio.create_task一起学习,gather适合已知任务数量的场景,create_task更适合动态添加任务的场景。不过这篇文章已经非常好了!

    5. CharlotteGarcia CharlotteGarcia

      I'm coming from JavaScript async/await and the concepts transfer almost perfectly. This article helped me understand the Python-specific nuances.

    6. 黄子涵 黄子涵

      以前总搞不清楚await到底在等什么,现在明白了是在等可等待对象准备好。普通对象不能等,因为事件循环不知道什么时候恢复。

    7. LiamJones LiamJones

      The distinction between concurrency and parallelism is subtle but crucial. You explained it perfectly with the sleep timing example.

    8. 吴思敏 吴思敏

      作为一个写爬虫的开发者,这篇文章帮我重构了整个项目。现在同时请求几十个页面速度提升了3倍,感谢!

    9. EllaBrown EllaBrown

      The analogy of “handing control back to event loop” finally makes sense. It's like a waiter taking orders instead of waiting for each dish to cook.

    10. 孙浩然 孙浩然

      gather让三个请求0.5秒完成这个例子太震撼了,之前写爬虫都是串行请求,难怪那么慢。这下知道怎么优化了。

    11. MasonWilliams MasonWilliams

      I wish more tutorials included the “common mistakes” section. The TypeError examples are exactly the errors I've been getting.