AIOHTTP vs HTTPX:Python 异步 HTTP 库全面对比
HTTPX 和 AIOHTTP 是 Python 中两款很受欢迎的 HTTP 库。下面这篇文章会对它们的相同点与不同点做一次系统对比,帮助你判断:你的任务更适合用哪一个。
在开发需要访问远程服务器或向远程服务器发送数据的应用时,发送 Web 请求几乎是绕不过去的基础能力。在 Python 生态中,事实上的底层库是 urllib3;但由于它本身相对复杂,大家后来更愿意把第三方 HTTP 客户端 Requests 当成标准方案。包括我自己在内,大多数脚本开发时也经常用 Requests。
不过,在某些方面,其他 HTTP 库比 Requests 做得更好,比如 HTTPX、httplib2、AIOHTTP 和 GRequests。本文重点讨论的是 HTTPX 和 AIOHTTP。我会带你比较这两个库,帮助你为自己的任务选出更合适的那个。在正式开始之前,我们先分别快速看一下它们各自是什么。
什么是 AIOHTTP?
AIOHTTP 是一个功能强大的 Python 异步 HTTP 客户端/服务器框架,专门为高效处理并发连接而设计。它基于 asyncio 模块实现非阻塞 I/O,因此很适合那些需要处理大量并发连接的应用。这个库可以通过下面这条命令从 PyPI 安装。
pip install AIOHTTP
执行上面的命令后,会安装 AIOHTTP 以及它的全部依赖项,包括 async_timeout、attrs、multidict 和 yarl。AIOHTTP 的一个关键特性是它支持 middleware(中间件),这意味着你可以编写可复用组件,并把这些组件统一应用到所有请求上。
什么是 HTTPX?
和同时覆盖服务端与客户端能力的 AIOHTTP 不同,HTTPX 是一个专门用于发送 HTTP/HTTPS 请求的客户端库。它建立在与 Requests 类似的设计思路之上,但更现代,也引入了更多高级能力,尤其是在性能优化和异步编程方面。
HTTPX 的一个优势是支持 HTTP/2 协议。这个协议相对更新,能够带来更快、更高效的通信体验。
它还支持基于流的响应处理、TLS、自定义请求头、认证、以及 JSON/XML 序列化。更有意思的是,它的 API 和 Requests 很相似,因此兼容思路也很接近,你可以比较轻松地在 HTTPX 与 Requests 之间来回切换。下面是安装 HTTPX 的命令。
pip install httpx
AIOHTTP 和 HTTPX 有哪些相似之处?
AIOHTTP 和 HTTPX 在不少方面功能相近,也共享一些共同特征,因此在某些任务里,用其中一个和用另一个,体验会很接近。在这一部分里,我会先看看它们相同的地方;讲完这些之后,再进入真正决定选型的差异部分。
异步支持
这两个库最重要的共同点之一,也是很多人除了更流行的 Requests 之外,会考虑使用它们的主要原因,就是它们都支持异步。需要注意的是,httpx 同时支持异步和同步操作,而 AIOHTTP 则是从一开始就围绕异步构建的。
在发送 Web 请求的场景中,“异步”意味着可以同时发送多个请求,而不会出现一个线程阻塞另一个线程的情况。这两个库都支持异步发送 Web 请求,而且都使用 asyncio 模块来实现。
都支持 HTTP 请求/响应处理
这两个库都可以作为 HTTP 客户端,能够发送请求并处理响应,而且支持范围很完整:GET、PUT、DELETE、POST 等各类请求都可以发送。它们也都允许你自定义 HTTP 请求头,并提供认证能力。整体来说,在 HTTP 功能支持这一层面上,HTTPX 和 AIOHTTP 非常接近。
都能与其他 Asyncio 库集成
这两个库都能很好地与那些兼容 Asyncio 的 Python 异步库配合使用。举个例子,当你开发一个异步 Web 爬虫时,只靠 HTTPX 或 AIOHTTP 其中之一其实是不够的;你还需要其他配套库也支持异步。像 aiomysql 这样的库,就是 MySQL 的一个不错替代方案,而且它和这两个库都能很好集成。
HTTPX 和 AIOHTTP 的区别
它们既然有相似之处,自然也有差异;而真正应该重点关注的,其实正是这些差异,因为它们会直接决定你在项目里该选哪一个。下面就来看几个关键区别。
同步支持
在上面的相似点部分,我提到这两个库都支持异步操作,并且都借助 asyncio 来实现。这意味着在异步编程层面,它们确实很像。但在同步编程方面——也就是一个线程阻塞另一个线程,必须等前一个任务完成后才能继续——它们就明显不同了。
HTTPX 的主要设计方向虽然是异步编程,但它也通过
httpx.Client类支持同步编程。有了它,操作就会从非阻塞模式切换成阻塞模式,也就是说,每一个请求都会占住线程,直到自身执行完成。这也限制了线程的并发方式。正因为如此,HTTPX 与 Requests 的兼容性更强,因为 Requests 本身就是同步库,而且两者 API 风格也比较接近。
相比之下,AIOHTTP 是从底层开始就为异步而设计的。从发送 Web 请求、向 socket 写入数据,到读取响应,它的所有操作都围绕异步模式构建。
它并不支持同步编程。因此,如果你想从同步库迁移到 AIOHTTP,就会遇到兼容性问题,因为你往往需要对现有代码做较大幅度的改造。就同步/异步这一点而言,HTTPX 的适用面更广,因为它两种都支持;AIOHTTP 则只支持异步编程。
定位重点
这里说的“定位”,指的是你可以把每个库用于哪些场景。HTTPX 很轻量,本质上就是一个 HTTP 客户端库。你可以把它理解成 Requests 的一个异步化、现代化替代品,而且它把这件事做得相当不错。
而 AIOHTTP 不一样,它的应用范围更广。使用 AIOHTTP 时,你手里拿到的是一个既能当客户端、也能当服务器的工具。也就是说,除了完成 HTTPX 能做的客户端请求工作之外,它还可以充当 Web 服务器。
它的 Web 服务器能力还支持 middleware,这让你可以编写能挂入请求/响应生命周期的可复用组件。它也支持 signals 和自定义路由,因此非常适合用来开发小型、可扩展的 Web 服务器。
如果只看定位范围,AIOHTTP 的能力显然更强,因为它既能写服务端,也能写客户端应用;而 HTTPX 只面向客户端编程。
现代感与 API 设计
HTTPX 是在 2019 年才推出的,相比之下,AIOHTTP 稍早一些,自 2016 年起就已经存在。总体上说,AIOHTTP 目前更流行,部分原因也确实是它出现得更早、积累时间更久。
不过,HTTPX 清爽、现代的风格也帮助它迅速获得了越来越多开发者的认可。从 API 设计和可读性角度看,HTTPX 通常被认为更整洁、更现代,而且整体感觉也更像大家熟悉的 Requests 客户端库。
这一点和 AIOHTTP 很不一样。AIOHTTP 的 API 往往被认为更啰嗦、更复杂,虽然它在很多场景下依然完全够用、也很实用。但从功能与特性角度讲,HTTPX 又因为支持 HTTP/2,以及更高级的请求定制能力,而显得更现代一些。
总的来说,HTTPX 凭借更现代的设计与功能逐渐获得广泛接受;而 AIOHTTP 虽然能用、也成熟,但经常会给人一种偏冗长的感觉。
性能
从前面的相似点可以看出,这两个库都面向异步场景而生。不过,前面没有说明的是:它们两者之间,究竟谁的性能更强?在性能方面,Oxylabs 团队做过一份相当不错的对比测试,比较了 AIOHTTP 和 HTTPX。你可以点击这里进一步了解这两个库的性能对比。
在一次发送 100 个异步请求的测试中,AIOHTTP 用 1.19 秒完成,而 HTTPX 用了 1.22 秒。这个差距几乎可以忽略不计。但当请求数量提升到 1000 个时,差异就开始明显了。
在 1000 个请求的测试里,AIOHTTP 用 3.79 秒完成,而 HTTPX 则用了 10.22 秒。基于这个结果,我们可以说:在高规模异步请求下,AIOHTTP 的性能更强。不过你也要注意,这其实是一个“规模效应”问题。
如果你需要发送大量请求,AIOHTTP 可能真的会带来明显差异;但如果请求量不大,那么在速度上你未必能感受到什么显著优势。
如何选择合适的库?
看到这里,你应该已经对 HTTPX 和 AIOHTTP 的相同点与不同点都有了比较清晰的认识。通常来说,真正决定你该选哪个的,并不是它们的相似之处,而是差异所在。
你需要知道,这两个库本身都很好用,也都属于优秀的 HTTP 客户端库,没有哪个能对所有任务做到 100% 完美适配。你必须结合具体条件做选择。下面就来看几个最实际的判断维度。
项目需求
只要你的项目有明确需求,那它就是决定你该用哪个库的第一因素。需求里是否明确规定了必须使用某个特定库?如果是,那你就只能照做。
如果没有明确指定,那你就应该认真分析需求本身,看哪个库更符合实际需要。比如,如果需求明确要求使用 HTTP/2,那么答案就很清楚:只能选 HTTPX,因为另一个并不支持这一点。
另外,你是否还需要开发服务端应用,希望同一个库既能处理客户端请求,又能承担服务端功能?如果答案是肯定的,那 AIOHTTP 就更合适。项目需求里还可能涉及一些更细的条件,例如是否要求同步支持;在这种情况下,两者中只有 HTTPX 能满足。
性能要求
速度表现是否很重要,甚至是不是决定性因素?如果是,那你就必须看谁更快。还是以前面的例子来说:当你发送 100 个异步请求时,它们之间的速度差不到 500 毫秒。
在这种情况下,如果仅仅因为这点速度差,就强行选择更快的那个,其实并不算理性的决策,因为对于 100 个请求来说,这点优势几乎没有实际意义。但当我们把规模提升到 1000 多个请求时,差异就明显了:AIOHTTP 快了 6.43 秒。
这时候,这个差距就已经足够大了。不过,单独有这个差异也还不够,前提是:性能对你的业务真的重要,甚至 1 秒钟的延迟都可能带来明显影响。比如做体育博彩套利时,AIOHTTP 就会更占优势,因为它可以在更短时间内抓取更多赔率,并且在大量赛事上反复快速执行这件事,而 HTTPX 在这种场景下就会慢一些。
易用性
另一个关键判断因素是:你是否需要一个更容易上手的方案。前面已经提到,HTTPX 的接口更整洁、更现代,也更直观,因此整体使用体验会更轻松。如果你本来就熟悉 Requests,那么它的学习曲线会更平缓,因为两者 API 风格很相似。
而 AIOHTTP 则不太一样。它通常会被认为更啰嗦、更复杂。但这并不代表它功能差,只是意味着:如果你是新手,你可能需要花更多时间去理解它的 API,以及如何用它把事情做好。即便熟悉之后,有些场景下,使用 AIOHTTP 写出来的代码也可能比 HTTPX 更长一些。
结论
归根到底,“HTTPX 和 AIOHTTP 到底谁更好”这个问题,并没有标准答案,因为结果取决于你的具体场景。如果你的项目特别看重性能,或者你还需要开发服务端,那么 AIOHTTP 往往是更好的选择。
但如果你更想要一个设计现代、API 干净、易于使用,并且还支持同步请求的库,那么 HTTPX 会更适合你。它们两者本身都很优秀,都支持异步请求,也都具备不错的请求定制能力。
原文来源:Best Proxy Review — AIOHTTP Vs. HTTPX: A Comprehensive Comparison Of Python’s Asynchronous HTTP Libraries