libcurl的share interface与curl_easy_perform的性能

通过使用libcurl的share interface,可以在不重用curlhandle的情况下让多个HTTP连接共享同一个DNS缓存,从而提高curl_easy_perform方法的执行效率。
部署运行你感兴趣的模型镜像

 

最近在使用libcurl实现客户端程序和http server通讯功能的时候,发现libcurl的性能不好。

具体情况是我在每次http连接时初始化一个新的curl handle,参数设置完成后,调用curl_easy_perform方法执行本连接。 如果程序中需要用到http连接比较少,感觉不到异常。但在测试中发现,程序需要大量http连接的时候,curl_easy_perform的性能很差。

调查发现,在curl_easy_perform方法每次执行时,libcurl都会启动一个线程,执行结束后结束这个线程。经研究libcurl的源代码发现,libcurl在curl_easy_perform方法中启动的线程用于做DNS解析, libcurl对于每一个curl hanlle有一个DNS cache,默认超时时间为60秒,如果不重用curl handle的话,这个dns cache在连接完成后就被析构了。我的程序没有重用curl handle,所以每个连接都会去启动线程做DNS解析。

问题来了,在不重用curl handle的情况下,怎么保证DNS cache一直有效,各个不同的curl handle能共用这个DNS cache呢?答案是有的,有个CURLOPT_DNS_USE_GLOBAL_CACHE设置,可以让libcurl所有http连接都使用一个全局的DNS cache。但是在查阅libcurl文档的时候,看到下面一段话:

15.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE

Remove support for a global DNS cache. Anything global is silly, and we already offer the share interface for the same functionality but done "right". 

也就是CURLOPT_DNS_USE_GLOBAL_CACHE将会在以后版本被去除掉,原因是设置CURLOPT_DNS_USE_GLOBAL_CACHE后虽然能够使用全局DNS cache,但任何全局的东西都是愚蠢的,而且libcurl已经提供了share interface可以用恰当的方式做同样的事。

在使用share interface的curl_share_init初始化share handle以后,使用curl_share_setopt设置共享对象,目前可以支持cookie和dns,在每一个curl handle执行前,使用CURLOPT_SHARE选项把这个share handle设置给curl handle,这样多个curl handle就可以共用同一个DNS cache了,代码如下:

 

 

注意,默认的DNS cache的超时时间为60秒,如果想把超时设得大一些,可以使用CURLOPT_DNS_CACHE_TIMEOUT选项来设置,如上将超时时间设为5分钟。

用share interface的话,我们在程序中可以灵活配置具体哪些http连接使用哪些DNS cache。在超时时间内,每次curl_easy_perform执行时不会再启动解析DNS的线程了,效率大大提高。

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

在使用 `libcurl` 的 `curl_easy_perform` 函数时,出现内存泄漏(memory leak)或内存耗尽(Out of memory)问题,通常资源未正确释放、重复调用不当、或底层库(如 OpenSSL)的配置问题有关。以下是一些排查和解决此类问题的建议和调试方法。 ### 1. 检查 `libcurl` 的初始化清理流程 确保每次调用 `curl_easy_perform` 之前都正确调用了 `curl_easy_init`,并在操作完成后调用 `curl_easy_cleanup`。如果未正确释放句柄,可能导致内存累积泄漏。 ```c CURL *curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); // 设置其他选项... CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { // 处理错误 } curl_easy_cleanup(curl); } ``` ### 2. 使用 `curl_global_init` 和 `curl_global_cleanup` 在程序启动时调用 `curl_global_init(CURL_GLOBAL_DEFAULT)`,并在程序退出前调用 `curl_global_cleanup()`,以确保全局资源被正确释放[^1]。 ### 3. 启用 `libcurl` 的调试输出 通过设置 `CURLOPT_DEBUGFUNCTION` 或使用 `CURLOPT_VERBOSE` 选项,可以启用详细的调试信息,帮助识别潜在的资源分配问题。 ```c curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); ``` ### 4. 使用内存分析工具检测泄漏 借助内存检测工具(如 Valgrind、AddressSanitizer)可以帮助定位内存泄漏的具体位置。 - **Valgrind 示例命令:** ```bash valgrind --leak-check=full --show-leak-kinds=all ./your_program ``` - **AddressSanitizer 编译选项:** ```bash gcc -fsanitize=address -g your_program.c -o your_program -lcurl ``` 这些工具能报告未释放的内存块及其调用栈,有助于追踪 `libcurl` 或其依赖库中的资源泄漏。 ### 5. 更新或统一依赖库版本 内存问题有时底层依赖库(如 OpenSSL、libssl、libz)版本不兼容有关。尝试更新 `libcurl` 及其依赖库到最新稳定版本,或确保系统中没有多个冲突的 OpenSSL 实例加载。 ### 6. 避免在多线程中共享 `CURL` 句柄 每个线程应使用独立的 `CURL` 句柄,避免在多个线程间共享未加锁的句柄,这可能导致不可预测的行为和内存问题。 ### 7. 检查 SSL/TLS 相关配置 如果使用了 HTTPS 请求,SSL 层(如 OpenSSL)也可能导致内存泄漏。可以尝试设置 SSL 会话复用选项或禁用不必要的 SSL 功能: ```c curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); ``` 此外,检查是否加载了多个 OpenSSL 版本,这可能导致资源管理混乱[^1]。 ### 8. 使用 `curl_multi_perform` 替代方案 如果并发请求较多,考虑改用 `curl_multi_perform` 接口进行异步处理,其资源管理更为高效,适合高并发场景。 ### 9. 检查自定义写回调函数 如果设置了 `CURLOPT_WRITEFUNCTION` 或 `CURLOPT_HEADERFUNCTION`,请确保这些回调函数正确处理数据,避免在回调中分配内存但未释放的情况。 ```c size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { // 确保正确管理 userdata 的内存 // 例如:将数据追加到缓冲区后不发生泄漏 return size * nmemb; } ``` ### 10. 查阅官方文档和社区反馈 参考 [libcurl 官方文档](https://curl.se/libcurl/c/) 和 GitHub、Stack Overflow 上的讨论,查看是否已有类似问题的解决方案。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值