深入理解异步编程:使用 `asyncio` 和 `aiohttp` 进行并发请求
深入理解异步编程:使用 `asyncio` 和 `aiohttp` 进行并发请求
在现代的Web开发中,性能优化是一个非常重要的课题。特别是在处理大量网络请求时,如何高效地利用资源,减少等待时间,是每个开发者都需要面对的问题。Python 的 asyncio
库为我们提供了一种强大的工具,可以轻松实现异步编程,从而提高程序的并发性能。本文将通过一个具体的例子,详细讲解如何使用 asyncio
和 aiohttp
进行并发网络请求。
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
: 使用aiohttp
的ClientSession
发送 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. 总结
通过这个例子,我们可以看到 asyncio
和 aiohttp
的强大之处。它们使得并发编程变得简单而高效,特别适合处理大量网络请求的场景。对于初级 Python 程序员来说,掌握异步编程是一个非常有价值的技能,它不仅能提高代码的性能,还能让你的程序更加现代化和高效。
原文地址:https://blog.csdn.net/engchina/article/details/144163557
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!