Python异步编程实战:用async/await构建高并发爬虫与API

2026-05-11 0 550

2025年,异步编程已成为Python高并发场景下的标配技能。无论是爬取千级页面,还是构建高性能API,async/await + asyncio都能让I/O密集型任务近乎线性加速。本文从一个完整的“异步图片爬虫”案例切入,逐步拆解协程、事件循环、任务编排等核心概念,并扩展至异步Web服务,帮你彻底掌握Python异步编程

一、为什么你需要异步编程?

传统同步代码在遇到I/O操作(如网络请求、文件读写)时会阻塞线程,导致CPU空闲等待。而异步编程通过协程(Coroutine)在单个线程内实现任务的协作式切换:遇到I/O等待时自动挂起,执行其他任务,待I/O完成再恢复。这使得单线程也能承载数千个并发连接,资源消耗远低于多线程/多进程。

Python的asyncio模块提供了事件循环(Event Loop)来调度协程。配合async/await语法,代码看起来和同步代码几乎一样,但内部却是非阻塞的。

二、核心概念:协程、可等待对象与事件循环

  • 协程函数:使用async def定义的函数。调用它不会立即执行,而是返回一个协程对象。
  • 可等待对象:协程、Task、Future。使用await可以挂起当前协程,等待结果。
  • 事件循环:运行协程的调度器。通过asyncio.run()启动。

下面是最简入门代码:

import asyncio

async def say_hello():
    print("Hello")
    await asyncio.sleep(1)   # 模拟I/O等待
    print("World")

asyncio.run(say_hello())

asyncio.sleep(1)是非阻塞的:在等待的1秒内,事件循环可以执行其他协程。

三、实战案例:异步图片爬虫(并发下载20张图)

我们以Lorem Picsum提供的随机图片为例,用aiohttp实现高并发下载。先安装依赖:pip install aiohttp

3.1 定义异步下载函数

import aiohttp
import asyncio
import os

SAVE_DIR = "async_images"
os.makedirs(SAVE_DIR, exist_ok=True)

async def download_one(session, url, index):
    print(f"开始下载第 {index} 张: {url}")
    async with session.get(url) as response:
        if response.status == 200:
            content = await response.read()
            file_path = os.path.join(SAVE_DIR, f"img_{index}.jpg")
            with open(file_path, "wb") as f:
                f.write(content)
            print(f"第 {index} 张下载完成,大小: {len(content)} 字节")
        else:
            print(f"第 {index} 张下载失败,状态码: {response.status}")

注意:session.getresponse.read()都是异步非阻塞的,await会挂起当前协程直到数据就绪。

3.2 编排并发任务

async def main():
    # 创建共享会话(连接池复用)
    async with aiohttp.ClientSession() as session:
        tasks = []
        # 生成20个不同的图片URL(picsum.photos 随机返回图片)
        for i in range(20):
            url = f"https://picsum.photos/800/600?random={i}"
            task = asyncio.create_task(download_one(session, url, i+1))
            tasks.append(task)
        # 等待所有任务完成
        await asyncio.gather(*tasks)

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

asyncio.create_task()将协程包装成Task并立即调度到事件循环。asyncio.gather()等待所有Task完成。运行脚本,你将看到图片几乎同时开始下载,总耗时仅相当于单张最慢下载时间,而非20倍。

3.3 运行效果与性能对比

在普通网络下,同步顺序下载20张图约需40~60秒,而异步并发版本仅需3~5秒(取决于网络带宽)。这是因为等待I/O时CPU在干其他活。

四、进阶技巧:信号量控制并发数与异常处理

如果无限制并发,可能会被目标网站封IP或导致本地资源耗尽。使用asyncio.Semaphore控制同时进行的任务数:

sem = asyncio.Semaphore(5)  # 最多5个并发

async def download_with_sem(session, url, index):
    async with sem:   # 获取信号量
        return await download_one(session, url, index)

# 在main中创建任务时使用 download_with_sem 即可

另外,asyncio.gather默认一任务异常就取消其他任务。若想每个任务独立,可设置return_exceptions=True

results = await asyncio.gather(*tasks, return_exceptions=True)
for r in results:
    if isinstance(r, Exception):
        print(f"任务异常: {r}")

五、扩展:构建一个异步Web API (基于aiohttp)

异步编程不仅用于客户端,也适用于服务端。下面用aiohttp搭建一个简易API,返回图片下载状态。

5.1 服务端代码

from aiohttp import web

async def handle_download(request):
    # 模拟异步下载任务
    await asyncio.sleep(2)
    return web.json_response({"status": "downloaded", "url": str(request.url)})

app = web.Application()
app.router.add_get('/download', handle_download)

if __name__ == '__main__':
    web.run_app(app, port=8080)

启动后访问 http://localhost:8080/download,2秒后返回JSON。由于是异步,同时处理100个请求时,每个请求都不会阻塞其他请求。

5.2 压测简单对比

使用wrkab工具对同步Flask和异步aiohttp进行压测(模拟100并发),你会发现aiohttp的吞吐量是Flask的3~5倍以上,而内存占用更低。

六、常见陷阱与最佳实践

  • 不要在协程中使用阻塞库:如requeststime.sleep()。它们会阻塞整个线程,破坏异步效果。应使用aiohttpasyncio.sleep()等。
  • 慎用同步锁:多线程锁(如threading.Lock)在协程中无效,应使用asyncio.Lock
  • 避免创建过多Task:大量任务可能导致内存飙升。推荐使用Semaphoreasyncio.Queue进行限流。
  • 使用asyncio.run()作为入口:它会自动创建事件循环、管理协程生命周期,并清理资源。

七、总结

Python异步编程通过async/await + asyncio让单线程并发变得优雅且高效。本文从协程基础出发,完成了异步图片爬虫和简单API两个实战案例,并介绍了信号量控制、异常处理等进阶技巧。掌握这些,你就能在爬虫、Web服务、消息队列等场景中轻松驾驭高并发。

下一步可以尝试结合aiofiles做异步文件操作,或使用FastAPI(基于asyncio)构建生产级API。异步编程的世界远不止于此,但你已经拿到了最重要的钥匙。


本文所有代码均在 Python 3.10+ 环境下测试通过。如果你在运行中遇到问题,欢迎交流探讨。

Python异步编程实战:用async/await构建高并发爬虫与API
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 python Python异步编程实战:用async/await构建高并发爬虫与API https://www.taomawang.com/server/python/1782.html

下一篇:

已经没有下一篇了!

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务