PHP并发请求优化:使用`curl_multi_select()`实现高效的多请求处理

PHP并发请求优化:使用curl_multi_select()实现高效的多请求处理

背景

最近在项目中遇到一个需求,需要从多个 1 级网站(超过 200 个)获取数据,并且是通过 POST 请求瞬间发送到这些网站上。开始时我直接使用了 curl_exec() 逐一发送请求,但是很快就发现了一个问题:这个方法是阻塞式的,只能一次发送一个请求。处理 200 多个请求时,性能非常差。显然,这种方法不适合大规模的并发请求。

为了解决这个问题,我查阅了大量资料,最后找到了一个不错的方案——使用 curl_multi_exec()curl_multi_select() 实现并发请求。这样不仅能大幅提升性能,还能避免 CPU 资源的浪费。下面是我的经验分享,希望对大家有帮助。

1. 为什么不用 curl_exec()

最开始,我像往常一样使用 curl_exec() 来发送请求,但是遇到了以下两个问题:

  1. 性能低下:每次只能处理一个请求,多个请求只能串行执行,耗时较长。
  2. 资源消耗大:频繁的网络请求导致 CPU 长时间空转,系统资源被大量占用。

显然,这样的方式不适合处理 200 多个并发请求,尤其是当项目需要高效、实时获取数据的时候。所以我需要找到一种更好的方式来实现并发请求。

2. 使用 curl_multi_exec() 实现并发请求

为了提升并发请求的效率,我决定使用 curl_multi_exec()。它可以将多个 cURL 请求组合在一起并行执行,从而大大提高了处理效率。

基本使用方法

首先,简单介绍一下如何使用 curl_multi_exec()。这个函数允许同时执行多个 cURL 请求,而不需要等待每个请求的完成。

$multiCurl = curl_multi_init();  // 初始化multi cURL句柄// 创建单个cURL请求
$ch1 = curl_init('https://example.com');
$ch2 = curl_init('https://example2.com');// 将单个cURL句柄加入multi句柄中
curl_multi_add_handle($multiCurl, $ch1);
curl_multi_add_handle($multiCurl, $ch2);// 执行并发请求
do {$status = curl_multi_exec($multiCurl, $active);
} while ($active && $status == CURLM_OK);// 关闭cURL句柄
curl_multi_remove_handle($multiCurl, $ch1);
curl_multi_remove_handle($multiCurl, $ch2);
curl_multi_close($multiCurl);

通过这种方法,我可以同时发送多个请求,而不必等待每个请求逐一完成。对比 curl_exec(),处理多个请求的效率提高了很多。

3. 优化:结合 curl_multi_select() 降低系统资源消耗

虽然 curl_multi_exec() 可以并发处理多个请求,但它本身并不会阻塞,因此我发现频繁调用它会导致系统的 CPU 资源大量消耗。这个问题在处理大量请求时尤其明显。

后来经过一番摸索,发现了 curl_multi_select()。这个函数可以阻塞进程,直到有请求完成或发生变化(如接收到数据等)。这样可以减少不必要的 CPU 占用,让系统只在有必要时才执行检查。

curl_multi_select() 的用法

通过 curl_multi_select(),我能有效减少 CPU 的空转等待。它的工作方式很简单:在等待时段内,如果有请求状态发生变化(比如完成、错误等),它就会继续执行。如果没有变化,进程会阻塞直到超时。

$multiCurl = curl_multi_init();// 创建多个cURL请求
$ch1 = curl_init('https://example.com');
$ch2 = curl_init('https://example2.com');// 添加请求句柄
curl_multi_add_handle($multiCurl, $ch1);
curl_multi_add_handle($multiCurl, $ch2);do {$status = curl_multi_exec($multiCurl, $active);if ($active) {// 使用 curl_multi_select 等待请求状态的变化,避免频繁CPU循环curl_multi_select($multiCurl);}} while ($active && $status == CURLM_OK);// 获取并处理每个请求的响应
curl_multi_remove_handle($multiCurl, $ch1);
curl_multi_remove_handle($multiCurl, $ch2);
curl_multi_close($multiCurl);

在这段代码中,curl_multi_select() 用于等待活动发生,只有当请求完成或者有数据时,才会继续执行,节省了 CPU 资源。

4. 实际应用:批量并发请求

为了处理项目中的大规模并发请求,我最终实现了一个可以同时发送多个请求的批处理脚本。以下是完整代码:

<?php// 初始化multi cURL句柄
$multiCurl = curl_multi_init();
$curlHandles = [];// 准备多个URL
$urls = ['https://example.com','https://example2.com','https://example3.com','https://example4.com'
];// 创建cURL句柄并将其添加到multi句柄中
foreach ($urls as $i => $url) {$ch = curl_init($url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回结果而不是直接输出$curlHandles[$i] = $ch;curl_multi_add_handle($multiCurl, $ch);
}do {$status = curl_multi_exec($multiCurl, $active);if ($active) {// 阻塞等待直到有请求完成curl_multi_select($multiCurl);}} while ($active && $status == CURLM_OK);// 获取并处理每个请求的响应
foreach ($curlHandles as $i => $ch) {$response = curl_multi_getcontent($ch);echo "Response from URL {$urls[$i]}: $response\n";curl_multi_remove_handle($multiCurl, $ch);  // 移除句柄
}// 关闭multi句柄
curl_multi_close($multiCurl);

通过这个方法,我成功实现了向 200 多个 1 级网站同时发起 POST 请求的需求,速度比最初的逐一请求快了很多倍。而且系统资源消耗也得到了很好的控制,避免了 CPU 的过度占用。

5. 总结

通过使用 curl_multi_exec()curl_multi_select(),我们可以大幅提升 PHP 中并发请求的处理效率,特别是当需要处理大量外部请求时。这种方法不仅能提高响应速度,还能有效降低系统资源的消耗,是非常适合大规模并发处理的解决方案。

希望这篇文章能为大家提供一些帮助,如果有类似需求的开发者也可以尝试这个方法。有什么问题或建议,欢迎留言交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/72798.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【leetcode hot 100 206】反转链表

解法一&#xff1a;&#xff08;头插法&#xff09;在遍历链表时&#xff0c;将当前节点的 next 指针改为指向前一个节点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val)…

【QT】-易错点笔记-2025-2-7

1,QList<phy_simulator*> pList;为空不能append()追加,要先new,再用 QList<phy_simulator> pList为空时,确实不能调用 append() 方法。原因很简单,QList 是一个类对象,在 C++ 中,指针本身并不代表它指向的对象。因此,当你有一个指向 QList<phy_simulato…

AI-Deepseek + PPT

01--Deepseek提问 首先去Deepseek问一个问题&#xff1a; Deepseek的回答&#xff1a; 在汽车CAN总线通信中&#xff0c;DBC文件里的信号处理&#xff08;如初始值、系数、偏移&#xff09;主要是为了 将原始二进制数据转换为实际物理值&#xff0c;确保不同电子控制单元&…

实验一:在Windows 10/11下配置和管理TCP/IP

目录 1.【实训目标】 2.【实训环境】 3.【实训内容】 4.【实训步骤】 1.【实训目标】 1.了解网络基本配置中包含的协议、服务、客户端。 2.了解Windows支持的网络协议及参数设置方法。 3.掌握TCP/IP协议的配置。 2.【实训环境】 硬件环境&#xff1a;每人一台计算机&a…

Java直通车系列14【Spring MVC】(深入学习 Controller 编写)

目录 基本概念 编写 Controller 的步骤和要点 1. 定义 Controller 类 2. 映射请求 3. 处理请求参数 4. 调用业务逻辑 5. 返回响应 场景示例 1. 简单的 Hello World 示例 2. 处理路径变量和请求参数 3. 处理表单提交 4. 处理 JSON 数据 5. 异常处理 基本概念 Cont…

EA - 开源工程的编译

文章目录 EA - 开源工程的编译概述笔记环境备注x86版本EABase_x86EAAssert_x86EAThread_x86修改 eathread_atomic_standalone_msvc.h原始修改后 EAStdC_x86EASTL_x86EAMain_x86EATest_x86备注备注END EA - 开源工程的编译 概述 EA开源了‘命令与征服’的游戏源码 尝试编译. 首…

一招解决Pytorch GPU版本安装慢的问题

Pytorch是一个流行的深度学习框架&#xff0c;广泛应用于计算机视觉、自然语言处理等领域。安装Pytorch GPU版本可以充分利用GPU的并行计算能力&#xff0c;加速模型的训练和推理过程。接下来&#xff0c;我们将详细介绍如何在Windows操作系统上安装Pytorch GPU版本。 查看是否…

为解决局域网IP、DNS切换的Windows BAT脚本

一、背景 为解决公司普通人员需要切换IP、DNS的情况&#xff0c;于是搞了个windows下的bat脚本&#xff0c;可以对有线网络、无线网络进行切换设置。 脚本内容 echo off title 多网络接口IP切换工具:menu cls echo echo 请选择要配置的网络接口: echo echo 1. 有线网络&am…

uni_app实现下拉刷新

1. 在页面配置中启用下拉刷新 首先&#xff0c;你需要在页面的 pages.json 文件中启用下拉刷新功能。 {"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页","enablePull…

OpenCV计算摄影学(14)实现对比度保留去色(Contrast Preserving Decolorization)的函数decolor()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将彩色图像转换为灰度图像。它是数字印刷、风格化的黑白照片渲染&#xff0c;以及许多单通道图像处理应用中的基本工具。 cv::decolor 是 OpenCV…

Qt常用控件之 纵向列表QListWidget

纵向列表QListWidget QListWidget 是一个纵向列表控件。 QListWidget属性 属性说明currentRow当前被选中的是第几行。count一共有多少行。sortingEnabled是否允许排序。isWrapping是否允许换行。itemAlignment元素的对齐方式。selectRectVisible被选中的元素矩形是否可见。s…

关于 QPalette设置按钮背景未显示出来 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/146047054 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

PostgreSQL 安装与使用

下载地址: EDB: Open-Source, Enterprise Postgres Database Management 安装图形化安装界面安装。安装完后将bin目录配置到系统环境变量 执行psql -h localhost -p 5432 -U postgres 密码在安装过程中设置的 ​ 0、修改密码 ALTER USER sonar WITH PASSWORD 123456; 1、新…

【基础3】快速排序

核心思路 快速排序是Java中Arrays.sort()的实现原理&#xff0c;采用分治策略&#xff0c;通过选择基准元素&#xff0c;将数组分为两个子数组&#xff0c;使得左边元素 ≤ 基准元素 ≤ 右边元素&#xff0c;然后递归排序子数组。 举个简单的例子&#xff0c;图书管理员需要按…

FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求

FreeSWITCH 简单图形化界面40 - 使用mod_curl模块进行http请求 0、界面预览00、简介1、编译安装1.1 编辑模块配置文件 2、使用2.1 拨号规则GET 请求POST 请求JSON 数据 2.2 Lua 脚本GET 请求POST 请求JSON 数据 3 、示例3.1 示例 1&#xff1a;提交 CDR 到第三方接口3.2 示例 2…

Linux 开发工具

linux中&#xff0c;常见的软件安装方式---下载 yum/apt.rpm安装包安装源码安装 yum 查看软件包 通过yumlist命令可以罗列出当前⼀共有哪些软件包.由于包的数⽬可能⾮常之多,这⾥我们需要使⽤ grep 命令只筛选出我们关注的包.例如: # Centos $ yum list | grep lrzsz lr…

Agent革命:Manus如何用工作流拆解掀起AI生产力革命

一、现象级产品的诞生背景 2025年3月6日&#xff0c;一款名为Manus的AI产品在技术圈引发地震式传播。其官方测试数据显示&#xff1a;在GAIA基准测试中&#xff0c;基础任务准确率达86.5%&#xff08;接近人类水平&#xff09;&#xff0c;中高级任务完成率突破57%。这标志着A…

Linux13-TCP\HTTP

一、TCP粘包问题 1.TCP在接受数据时,多包数据粘在一起 2.原因: 2.1TCP发送数据时,会根据缓冲区数据的情况进行重新组包 2.2TCP接收方,没有及时读走缓冲区数据,导致缓冲区大量数据缓存。 3.如何解决 3.1发指定大小字节 将要发数据,封装在结构体里 struct data { …

网络安全等级保护2.0 vs GDPR vs NIST 2.0:全方位对比解析

在网络安全日益重要的今天&#xff0c;各国纷纷出台相关政策法规&#xff0c;以加强信息安全保护。本文将对比我国网络安全等级保护2.0、欧盟的GDPR以及美国的NIST 2.0&#xff0c;分析它们各自的特点及差异。 网络安全等级保护2.0 网络安全等级保护2.0是我国信息安全领域的一…

oracle通过dmp导入数据

1、创建用户&#xff0c;并赋予sysdba权限 登录sysdba用户 sqlplus / as sysdba 赋予sysdba权限 grant sysdba to your_user; 2、导入dmp文件 imp target_user/passwordip:port/SERVER_NAME fromusersource_user tousertarget_user fileyour.dmp logdmp_file.log statist…