我正在尝试用C++编写一个使用libcurl多接口的小程序,遇到了一个问题,它的执行速度比预期的要慢得多:对于一个静态HTML页面(由我在互联网上租用的小型虚拟机上的nginx提供)的49个请求(任意数量),它需要相当稳定的32秒。
在谷歌或GitHub上运行应用程序也需要同样长的时间,而在我的静态页面上使用
hey
yields >1500 requests/s, so I'm pretty sure it's not the servers fault. Looping over the
curl
command line application 50 times in a row is also quite a bit faster with just 13 seconds total.
下面是有关的代码(为了便于阅读,代码最小)。
#include <curl/curl.h>
#include <memory>
#include <string>
#include <vector>
struct Request {
std::shared_ptr<CURL> request;
int request(std::string url, CURLM *curlm, std::vector<Request> &requests) {
Request r = {
.request = std::shared_ptr<CURL>(curl_easy_init(), curl_easy_cleanup),
curl_easy_setopt(r.request.get(), CURLOPT_URL, url.c_str());
curl_multi_add_handle(curlm, r.request.get());
requests.push_back(r);
return 0;
int main(__attribute__((unused)) int argc, char *argv[]) {
curl_global_init(CURL_GLOBAL_ALL);
std::vector<Request> requests;
CURLM *multi = curl_multi_init();
// generate an arbitrary amount of requests
for(int i = 0; i < 49; i++)
request(std::string(argv[1]), multi, requests);
int running = 0;
curl_multi_perform(multi, &running);
int numfds = 0;
curl_multi_perform(multi, &running);
// select
fd_set fdread, fdwrite, fdexcep;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
struct timeval timeout = {
.tv_sec = 0,
.tv_usec = 500
curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &numfds);
select(numfds+1, &fdread, &fdwrite, &fdexcep, &timeout);
// or poll
//curl_multi_poll(multi, nullptr, 0, 1000, &numfds);
} while(running > 0);
return 0;
我在多个客户端系统上进行了测试:我的工作站是Ubuntu 20.04,结果可以在CentOS 8、Ubuntu 18.04和Debian 10(都是libcurl 7.60系列)上重现,然而在CentOS 7(libcurl 7.29.0)上,同样的代码在3-5秒内完成!除了我的工作站,我测试的所有这些系统都是新安装的虚拟机,运行在同一台主机上,有相同的网络配置。除了我的工作站之外,我测试的这些系统都是新安装的虚拟机,运行在同一台主机上,具有相同的网络配置。同时,互联网上的虚拟机(Debian 10,libcurl 7.64)和我期望的一样快,结果是亚秒。
使用Wireshark,我可以看到所有与网络服务器的连接都是一次性打开的,但实际的HTTP请求是分批发送的,而且间隔时间越来越长--最后一个请求是在打开连接后~30秒才发送的。
在select()
与使用curl_multi_poll()
的方式之间也没有时间上的差异,我已经翻阅了cURL文档,寻找可能提高性能的选项;启用流水线并没有带来任何区别,禁用HTTP2也没有,而且大多数限制(例如最大连接数)似乎都被默认设置为无限。
现在有趣的部分来了:当我通过strace运行这个应用程序时,在任何本地虚拟机上每次运行只需要2-4秒。起初我认为strace
可能会破坏事情,但是如果我通过shell重定向丢弃strace
的输出,看起来应用程序是正常工作的,那么是什么原因?
为什么使用strace
可以改善事情,什么原因可能导致运行时间在这些系统中出现巨大的差异?
有什么想法,我错过了什么?我的Google-fu这次离开了我。