Python 请求与 PyCurl 性能

Posted

技术标签:

【中文标题】Python 请求与 PyCurl 性能【英文标题】:Python Requests vs PyCurl Performance 【发布时间】:2013-03-05 21:56:22 【问题描述】:

Requests 库与 PyCurl 的性能相比如何?

我的理解是 Requests 是 urllib 的 python 包装器,而 PyCurl 是 libcurl 的原生 python 包装器,所以 PyCurl 应该会获得更好的性能,但不确定能提高多少。

我找不到任何比较基准。

【问题讨论】:

【参考方案1】:

首先,requests 构建在 urllib3 library 之上,根本不使用 stdlib urlliburllib2 库。

在性能上比较 requestspycurl 没有什么意义。 pycurl 可能使用 C 代码进行工作,但与所有网络编程一样,您的执行速度很大程度上取决于将您的机器与目标服务器分开的网络。此外,目标服务器可能响应缓慢。

最后,requests 有一个更友好的 API 可供使用,您会发现使用该更友好的 API 会提高工作效率。

【讨论】:

我同意对于大多数应用程序来说,请求的干净 API 最重要;但是对于网络密集型应用程序,没有理由使用 pycurl。开销可能很重要(尤其是在数据中心内)。 @BobMcGee:如果网络速度如此之高以至于开销很重要,那么您不应该再将 Python 用于整个应用程序。 @Martijn_Pieters 不同意——python 的性能还不错,而且通常很容易将性能敏感位委托给本地库(pycurl 就是一个很好的例子)。 DropBox 可以让它工作,yum 内部使用 pycurl(因为它的很多工作只是网络获取,需要尽可能快)。 @BobMcGee:是的,对于像 yum 这样的专业代码库来说,处理 pycurl API 的痛苦是值得的;对于绝大多数 URL 处理需求,但权衡很大程度上有利于requests。换句话说,大多数项目都不需要经历使用pycurl的痛苦;在我的观点中,您需要非常依赖网络,然后才值得放弃requests API;易于开发的差异是巨大的。 @MarijnPieters:完全同意!除非网络性能很关键(或者您需要低级别的 curl 功能),否则请求应该是默认的选择。为了完成这幅画,我们现在有了一个可以用来测试自己的基准。【参考方案2】:

I wrote you a full benchmark,使用由 gUnicorn/meinheld + nginx 支持的简单 Flask 应用程序(用于性能和 HTTPS),并查看完成 10,000 个请求需要多长时间。测试在 AWS 中在一对未加载的 c4.large 实例上运行,并且服务器实例不受 CPU 限制。

TL;DR 总结:如果您要进行大量网络连接,请使用 PyCurl,否则使用请求。 PyCurl 完成小请求的速度是请求的 2 到 3 倍,直到您达到大请求的带宽限制(此处约为 520 MBit 或 65 MB/s),并且使用的 CPU 功率减少了 3 倍到 10 倍。这些图比较了连接池行为相同的情况;默认情况下,PyCurl 使用连接池和 DNS 缓存,而请求不使用,因此简单的实现将慢 10 倍。

请注意,由于涉及的数量级,双对数图仅用于下图

在重用连接时,pycurl 需要大约 73 个 CPU 微秒来发出请求 重用连接时发出请求大约需要 526 CPU 微秒 pycurl 大约需要 165 CPU 微秒来打开一个新连接并发出请求(不重用连接),或者大约需要 92 微秒来打开 请求大约需要 1078 CPU 微秒来打开一个新连接并发出请求(不重用连接),或者大约需要 552 微秒来打开

Full results are in the link,以及基准测试方法和系统配置。

警告:虽然我努力确保以科学的方式收集结果,但它只测试一种系统类型和一种操作系统,以及有限的性能子集,尤其是 HTTPS 选项.

【讨论】:

您的基准测试很好,但 localhost 没有任何网络层开销。如果您可以在实际网络速度下限制数据传输速度,使用现实的响应大小(pong 不现实),并包括混合内容编码模式(有和没有压缩),那么 在此基础上生成时间,然后您将获得具有实际意义的基准数据。 我还注意到您将 pycurl 的设置移出循环(设置 URL 和 writedata 目标可以说是循环的一部分),并且不要读出 cStringIO 缓冲区;非 pycurl 测试都必须将响应生成为 Python 字符串对象。 @MartijnPieters 故意缺少网络开销;这里的目的是单独测试客户端。 URL 是可插入的,因此您可以针对您选择的真实实时服务器对其进行测试(默认情况下它不会,因为我不想敲打某人的系统)。 重点说明: pycurl后面的测试通过body.getvalue读取响应体,性能非常相似。如果您可以提出改进建议,欢迎对代码进行 PR。 @KennethReitz 是的,这是一个相当粗略的基准,如果您准备好改进,我欢迎 PR(并且可以在原始系统上重新运行以进行比较)!对于所有情况,我们确实应该在有和没有连接重用的情况下进行基准覆盖。这是因为一个人可能正在向不同的服务器发出请求,或者向同一个服务器发出一串请求。根据您的数据,我认为我们仍然没有错,说 pycurl 在相同的连接行为下快 3 倍到 10 倍。 @Martijn_Pieters 您可能想再看一遍,我已经更新了一个基准,其中包含 AWS 中的全部网络开销。【参考方案3】:

关注大小 -

    在配备 8GB RAM 和 512GB SSD 的 Mac Book Air 上,100MB 文件以每秒 3 KB 的速度传入(来自互联网和 wifi)、pycurl、curl 和 requests 库的 get 函数(无论分块或流式传输)几乎相同。

    在具有 4GB RAM 的较小 Quad core Intel Linux box 上,通过 localhost(来自同一机器上的 Apache),对于 1GB 文件,curl 和 pycurl 比“请求”库快 2.5 倍。对于请求,分块和流式传输一起提供 10% 的提升(块大小超过 50,000)。

我以为我必须将请求换成 pycurl,但不是这样,因为我正在制作的应用程序不会让客户端和服务器关闭。

【讨论】:

【参考方案4】:

似乎有一个新的孩子:- pycurl 的请求接口。

感谢您的基准测试 - 很好 - 我喜欢 curl,它似乎比 http 能做的更多。

https://github.com/dcoles/pycurl-requests

【讨论】:

以上是关于Python 请求与 PyCurl 性能的主要内容,如果未能解决你的问题,请参考以下文章

asyncio + pycurl + BytesIO 异步批量调用url请求

PyCurl 请求在执行时无限挂起

python之web服务质量探测(pycurl模块)

pycurl之公共方法--请求/上传/下载,解析json

Python 自动化运维 pycurl

python3 通过 pycurl 检测站点性能,各个环节返回时间