当前位置: 首页 > article >正文

深入理解异步编程:使用 `asyncio` 和 `aiohttp` 进行并发请求

深入理解异步编程:使用 `asyncio` 和 `aiohttp` 进行并发请求

        • 1. 异步编程简介
        • 2. 代码结构概览
        • 3. 代码详解
          • 3.1 `fetch` 函数
          • 3.2 `fetch_all` 函数
          • 3.3 `main` 函数
          • 3.4 主程序
        • 4. 性能分析
        • 5. 总结

在现代的Web开发中,性能优化是一个非常重要的课题。特别是在处理大量网络请求时,如何高效地利用资源,减少等待时间,是每个开发者都需要面对的问题。Python 的 asyncio 库为我们提供了一种强大的工具,可以轻松实现异步编程,从而提高程序的并发性能。本文将通过一个具体的例子,详细讲解如何使用 asyncioaiohttp 进行并发网络请求。

1. 异步编程简介

异步编程是一种编程范式,它允许程序在等待某些操作(如网络请求、文件读写等)完成时,继续执行其他任务,而不是阻塞等待。Python 3.4 引入了 asyncio 库,使得异步编程变得更加简单和直观。

2. 代码结构概览

我们先来看一下代码的整体结构:

import asyncio
import aiohttp
from time import perf_counter

async def fetch(s, url):
    async with s.get(f'http://127.0.0.1:8000/items/{url}') as r:
        if r.status != 200:
            r.raise_for_status()
        return await r.text()

async def fetch_all(s, urls):
    tasks = []
    for url in urls:
        task = asyncio.create_task(fetch(s, url))
        tasks.append(task)
    res = await asyncio.gather(*tasks)
    return res

async def main():
    urls = range(1, 2500)
    async with aiohttp.ClientSession() as session:
        htmls = await fetch_all(session, urls)
        print(htmls)

if __name__ == '__main__':
    start = perf_counter()
    asyncio.run(main())
    stop = perf_counter()
    print("time taken:", stop - start)
3. 代码详解
3.1 fetch 函数

fetch 函数负责发送单个请求并返回响应内容。它使用了 aiohttp 库来发送异步 HTTP 请求。

async def fetch(s, url):
    async with s.get(f'http://127.0.0.1:8000/items/{url}') as r:
        if r.status != 200:
            r.raise_for_status()
        return await r.text()
  • async with s.get(...) as r: 使用 aiohttpClientSession 发送 GET 请求,并异步等待响应。
  • if r.status != 200: 检查响应状态码,如果不是 200,则抛出异常。
  • return await r.text(): 返回响应的文本内容。
3.2 fetch_all 函数

fetch_all 函数负责并发地发送多个请求,并将所有请求的结果收集起来。

async def fetch_all(s, urls):
    tasks = []
    for url in urls:
        task = asyncio.create_task(fetch(s, url))
        tasks.append(task)
    res = await asyncio.gather(*tasks)
    return res
  • tasks = []: 创建一个空列表来存储所有的任务。
  • for url in urls: 遍历所有的 URL,为每个 URL 创建一个异步任务。
  • task = asyncio.create_task(fetch(s, url)): 使用 asyncio.create_task 创建一个任务,并将其添加到任务列表中。
  • res = await asyncio.gather(*tasks): 使用 asyncio.gather 并发执行所有任务,并等待所有任务完成。
  • return res: 返回所有任务的结果。
3.3 main 函数

main 函数是整个程序的入口,它负责初始化 aiohttp.ClientSession,并调用 fetch_all 函数来获取所有 URL 的响应内容。

async def main():
    urls = range(1, 2500)
    async with aiohttp.ClientSession() as session:
        htmls = await fetch_all(session, urls)
        print(htmls)
  • urls = range(1, 2500): 创建一个包含 2499 个 URL 的列表。
  • async with aiohttp.ClientSession() as session: 创建一个 aiohttp.ClientSession 对象,用于发送 HTTP 请求。
  • htmls = await fetch_all(session, urls): 调用 fetch_all 函数,获取所有 URL 的响应内容。
  • print(htmls): 打印所有响应内容。
3.4 主程序

在主程序中,我们使用 asyncio.run 来运行 main 函数,并计算整个程序的执行时间。

if __name__ == '__main__':
    start = perf_counter()
    asyncio.run(main())
    stop = perf_counter()
    print("time taken:", stop - start)
  • start = perf_counter(): 记录程序开始执行的时间。
  • asyncio.run(main()): 运行 main 函数。
  • stop = perf_counter(): 记录程序结束执行的时间。
  • print("time taken:", stop - start): 打印程序的执行时间。
4. 性能分析

在代码的最后,我们打印了程序的执行时间。通过这种方式,我们可以直观地看到异步编程带来的性能提升。在我的测试环境中,执行时间大约为 1.348 秒,这对于 2499 个并发请求来说是非常高效的。

5. 总结

通过这个例子,我们可以看到 asyncioaiohttp 的强大之处。它们使得并发编程变得简单而高效,特别适合处理大量网络请求的场景。对于初级 Python 程序员来说,掌握异步编程是一个非常有价值的技能,它不仅能提高代码的性能,还能让你的程序更加现代化和高效。


http://www.kler.cn/a/417301.html

相关文章:

  • springboot359智慧草莓基地管理系统(论文+源码)_kaic
  • Istio笔记01--快速体验Istio
  • linux tcpdump编译
  • Spring的事务管理
  • Opencv+ROS实现摄像头读取处理画面信息
  • qt QGraphicsPolygonItem详解
  • 性能测试工具Grafana、InfluxDB和Collectd的搭建
  • Linux - 时间服务器
  • springboot学习-spring-boot-data-jdbc分页/排序/多表查询的例子
  • 基于大数据python 房屋价格数据分析预测可视化系统(源码+LW+部署讲解+数据库+ppt)
  • ESP32-S3模组上跑通ES8388(10)
  • CommonJS 和 ES Modules 的 区别
  • uniapp配置全局消息提醒
  • Spring - RabbitMQ循环依赖问题解决
  • 【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-39
  • QT开发准则
  • JS中的类与对象
  • Axios:现代JavaScript HTTP客户端
  • 社交新零售模式下“2+1 链动模式 S2B2C 商城小程序”的创新实践与发展策略
  • flink学习(10)——allowedLateness/测道输出
  • redis快速进门
  • 贪心算法基础解析
  • 【文档搜索引擎】实现索引构建——解析标题、解析URL、解析正文
  • 【西瓜书】支持向量机(SVM)
  • golang append 相关面试题
  • python冒号是什么意思