Python 异步编程入门:用 asyncio 轻松实现并发任务

前言

在日常开发中,经常会遇到需要同时处理多个 IO 任务的场景,比如:

  • 同时请求多个接口
  • 批量下载文件
  • 并发查询数据库

如果使用传统的同步写法,任务只能一个接一个执行,总耗时就是所有任务耗时之和。而使用 Python 的 asyncio,可以在单线程内实现并发,大幅提升 IO 密集型任务的效率。

本文通过一个简单示例,带你快速入门 asyncio。


一、核心概念

asyncio 是 Python 标准库自带的异步 IO 框架,核心概念包括:

  • 协程(Coroutine) :用 async def 定义的函数
  • 事件循环(Event Loop):负责调度协程执行
  • 任务(Task):将协程包装成任务,交给事件循环调度
  • await:挂起当前协程,等待异步操作完成

简单理解:遇到 IO 等待时,await 会让出控制权,让其他任务先执行。


二、同步 vs 异步

假设有三个下载任务,分别耗时 2 秒、1 秒、3 秒。

同步执行总耗时约:

text 复制代码
2 + 1 + 3 = 6 秒

异步并发执行总耗时约:

text 复制代码
max(2, 1, 3) = 3 秒

下面用代码验证。


三、完整示例

python 复制代码
import asyncio
import time


async def download(name: str, delay: float):
    print(f"[{name}] 开始下载...")
    await asyncio.sleep(delay)  # 模拟网络 IO
    print(f"[{name}] 下载完成,耗时 {delay}s")
    return f"{name} 的结果"


async def main():
    start = time.perf_counter()

    tasks = [
        download("文件A", 2),
        download("文件B", 1),
        download("文件C", 3),
    ]

    results = await asyncio.gather(*tasks)

    end = time.perf_counter()
    print("执行结果:", results)
    print(f"总耗时: {end - start:.2f}s")


if __name__ == "__main__":
    asyncio.run(main())

运行结果:

text 复制代码
[文件A] 开始下载...
[文件B] 开始下载...
[文件C] 开始下载...
[文件B] 下载完成,耗时 1s
[文件A] 下载完成,耗时 2s
[文件C] 下载完成,耗时 3s
执行结果: ['文件A 的结果', '文件B 的结果', '文件C 的结果']
总耗时: 3.00s

可以看到,总耗时约等于最慢的任务,而不是所有任务之和。


四、控制并发数量

如果任务太多,一次性全部并发可能会导致资源耗尽。可以使用 Semaphore 限制并发数。

python 复制代码
import asyncio
import time

sem = asyncio.Semaphore(2)  # 最多同时执行 2 个任务


async def download(name: str, delay: float):
    async with sem:
        print(f"[{name}] 开始下载...")
        await asyncio.sleep(delay)
        print(f"[{name}] 下载完成")
        return name


async def main():
    start = time.perf_counter()
    tasks = [download(f"文件{i}", 1) for i in range(1, 6)]
    results = await asyncio.gather(*tasks)
    end = time.perf_counter()
    print("结果:", results)
    print(f"总耗时: {end - start:.2f}s")


if __name__ == "__main__":
    asyncio.run(main())

五、常见坑

  1. 忘记加 await

    协程函数调用后不会立即执行,必须用 await 或包装成 Task。

  2. 在协程中使用 time.sleep()

    time.sleep() 会阻塞整个事件循环,应该使用 await asyncio.sleep()。

  3. CPU 密集型任务不适合 asyncio

    asyncio 适合 IO 密集型任务。如果是 CPU 密集型,建议使用多进程。


六、总结

asyncio 是 Python 中非常实用的异步编程工具,特别适合爬虫、API 聚合、文件下载等 IO 密集型场景。

记住三个关键词:

  • async def 定义协程
  • await 等待异步操作
  • asyncio.gather 并发执行多个任务

掌握这些,就能写出高效又简洁的异步代码。

相关推荐
把我格子衫拿来1 小时前
Dice 很高就够了吗?分割评价中的 IoU、表面距离与 HD95
python·图像分割·模型评估·医学影像·dice
学逆向的1 小时前
C 循环结构的执行效率分析
c语言·开发语言·数据结构·网络安全
曲径海盗2 小时前
【Python 学习第 31 天】复习:变量与数据类型 等 3 题
python·学习笔记·编程入门
Data_Journal2 小时前
如何绕过 Cloudflare:网页抓取的最佳方法
网络·python
小坏讲微服务2 小时前
刚发布一个月的JDK 27,为什么我建议你立刻升级?
java·开发语言·spring boot·spring·架构·求职招聘·springboot4
我命由我123452 小时前
智能助手通用问答边界
人工智能·python·学习·ai·学习方法·ai编程·智能体
Angeldream1233 小时前
第 4 章 医学影像预处理
图像处理·人工智能·python·医学影像·医学影像处理
Web3&Basketball3 小时前
实测Gemini4Argon:ERQA 87%登顶长程任务榜
数据库·python·大模型·多模态·gemini·长上下文·推理优化
把我格子衫拿来3 小时前
医学影像重采样:spacing 改了,为什么模型位置也跟着错了?
python·dicom·医学影像·simpleitk·重采样