找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1689

积分

0

好友

221

主题
发表于 16 小时前 | 查看: 1| 回复: 0

最近公司在进行Python后端项目的重构,整个后端逻辑转向了异步协程的实现方式。面对满屏的 asyncawait,起初确实有些挑战,但在深入实践后,发现其带来的性能提升是显著的。今天,我们就来聊聊一个能极大提升网络请求效率的库——httpx,它几乎可以被视作异步版的 requests

什么是协程?

协程是一种比线程更轻量级的存在。简单来说,它是运行在用户空间的“轻量级线程”,由程序员自行调度管理。与多线程相比,协程有几个核心优势:

  1. 控制权在用户手中:线程的调度由操作系统控制,上下文切换开销大;而协程完全由用户控制,切换开销极小。
  2. 更轻量:一个线程通常需要分配MB级别的栈空间,而协程只需几KB,因此能在相同内存下运行更多并发任务。
  3. 避免锁机制:因为协程在单线程内交替执行,不存在真正的并行,从而避免了多线程编程中常见的资源竞争、死锁等问题。

协程特别适合处理I/O密集型任务,例如网络请求、文件读写等场景,它能让你在等待I/O时去执行其他任务,从而大幅提升程序整体吞吐量。但对于CPU密集型计算,协程的优势就不明显了,仍需依赖多进程或多线程。

为什么选择httpx?

理解了协程的优势,httpx 的价值就显而易见了。httpx 是一个完全支持异步HTTP请求的现代库,它几乎继承了 requests 所有人性化的API设计。对于习惯 requests 的开发者来说,迁移到 httpx 的学习成本极低。

安装非常简单,只需一条命令:

pip install httpx

使用httpx进行异步请求

让我们通过一个具体的对比,直观感受异步请求带来的效率提升。

同步请求示例

首先,我们回顾一下使用 requests 进行同步请求的典型写法:

import requests
import time

def sync_main(url, sign):
    response = requests.get(url)
    print(f'sync_main: {sign}: {response.status_code}')

sync_start = time.time()
[sync_main('http://www.baidu.com', i) for i in range(200)]
sync_end = time.time()
print(f'Total time for sync requests: {sync_end - sync_start} seconds')

这段代码顺序发送200次HTTP请求。运行结果大致如下:

sync_main: 0: 200
...
sync_main: 199: 200
Total time for sync requests: 16.6 seconds

可以看到,同步请求的总耗时约为16.6秒,大部分时间都花在了等待网络响应上。

异步请求示例

接下来,我们用 httpx 结合 asyncio 实现同样的功能:

import asyncio
import httpx
import time

async def async_main(url, sign):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        print(f'async_main: {sign}: {response.status_code}')

async def main():
    tasks = [async_main('http://www.baidu.com', i) for i in range(200)]
    await asyncio.gather(*tasks)

async_start = time.time()
asyncio.run(main())
async_end = time.time()
print(f'Total time for async requests: {async_end - async_start} seconds')

这段代码并发地发起200次请求。运行结果可能如下:

async_main: 0: 200
...
async_main: 199: 200
Total time for async requests: 4.5 seconds

异步请求总耗时仅需约4.5秒,相较于同步方式效率提升了近73%!这正是异步编程在处理I/O密集型任务时的威力。

深入理解httpx的功能特性

除了基础的异步请求,httpx 还提供了诸多强大且灵活的特性,使其在复杂场景下游刃有余。

1. 便捷的并发请求

httpxasyncio.gather 结合,可以轻松实现高并发数据抓取,是编写高效爬虫的利器。

import asyncio
import httpx

async def fetch(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.text

async def main(urls):
    tasks = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)
    return results

urls = ['http://example.com' for _ in range(100)]
results = asyncio.run(main(urls))
print(f'Fetched {len(results)} pages')

2. 安全的异步上下文管理

httpx.AsyncClient() 是一个异步上下文管理器,它能确保HTTP连接池等资源在使用后被正确关闭,这是编写健壮异步代码的最佳实践。

import httpx
import asyncio

async def fetch(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response

async def main():
    response = await fetch('http://example.com')
    print(response.text)

asyncio.run(main())

3. 灵活的超时与重试机制

网络请求中,超时和重试是保证稳定性的关键。httpx 对此提供了简洁的配置方式。

import httpx
import asyncio

async def fetch(url):
    async with httpx.AsyncClient(timeout=5.0) as client:
        response = await client.get(url)
        return response

async def main():
    try:
        response = await fetch('http://example.com')
        print(response.text)
    except httpx.TimeoutException:
        print('Request timed out')

asyncio.run(main())

这里我们为客户端设置了5秒的超时时间,一旦超时便会抛出 httpx.TimeoutException 异常。

httpx在实际项目中的应用场景

1. 高效数据抓取

在实际的爬虫或数据聚合项目中,经常需要批量获取API数据。使用 httpx 可以显著缩短任务时间。

import asyncio
import httpx

async def fetch_data(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.json()

async def main(urls):
    tasks = [fetch_data(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result)

urls = [f'http://api.example.com/data/{i}' for i in range(100)]
asyncio.run(main(urls))

2. 并发接口测试

在需要对大量API端点进行验证或压力测试时,httpx 的异步特性能够快速完成并发测试。

import asyncio
import httpx

async def test_api(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        assert response.status_code == 200

async def main(urls):
    tasks = [test_api(url) for url in urls]
    await asyncio.gather(*tasks)

urls = [f'http://api.example.com/test/{i}' for i in range(100)]
asyncio.run(main(urls))

总结

总的来说,httpx 是一个功能强大且设计优雅的HTTP客户端库。它完美结合了 requests 的易用性和现代Python异步生态的高性能。在处理需要大量并发网络请求的场景,如爬虫、微服务调用、接口测试等,httpx 都能带来质的效率提升。

如果你正在使用 requests 且面临性能瓶颈,或者你的项目正在向异步架构迁移,那么 httpx 绝对值得你深入尝试。希望本文的对比与实践示例能帮助你更好地理解和应用这个强大的工具。在云栈社区,你可以找到更多关于Python及异步编程的深度讨论和实战资源。




上一篇:离职电脑损坏赔偿引热议,算法题解LR字符串相邻字符交换规则
下一篇:Python异步HTTP请求库httpx实战:为何它能替代requests并提升接口测试效率?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-28 20:42 , Processed in 0.504516 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表