php不支持真正多线程,curl_multi通过i/o复用实现伪异步并发,基于select/poll/epoll轮询socket状态,按四步完成请求:初始化、添加句柄、exec+select驱动、info_read收集结果。

PHP 本身不支持真正的多线程(除非用 pthreads 扩展,但已废弃且不推荐),curl_multi 实现的是并发 I/O 复用,也就是常说的“伪异步”——它让多个 cURL 请求在单线程中并行发起、非阻塞等待响应,大幅提升批量 HTTP 请求效率。
curl_multi 的核心逻辑
它不是开多个线程,而是基于 select/poll/epoll(底层由 libcurl 封装)轮询多个 socket 句柄的状态,一旦某个请求完成(如收到响应头、数据就绪或出错),就立即处理,避免一个请求卡住整个流程。
关键四步:
父母的功课——育儿心理学对话支持技能(心虫增强版)。提供结构化对话、情绪识别、场景匹配与安全检测;可选Python脚本(scripts/)在SKILL_DIR/data/本地存储评估历史、洞察与会话状态,不对外传输。核心路径:觉察(看见防御)→接纳(慈悲是……
- 初始化 multi 句柄:
$mh = curl_multi_init(); - 逐个创建并添加普通 cURL 句柄(
curl_init()+curl_setopt()+curl_multi_add_handle()) - 循环调用
curl_multi_exec()驱动执行,配合curl_multi_select()等待 I/O 事件(避免忙等) - 用
curl_multi_info_read()检查已完成句柄,取出结果并清理
一个可直接运行的示例
同时请求 3 个 URL,获取状态码和响应体长度:
$urls = [
'https://httpbin.org/delay/1',
'https://httpbin.org/status/200',
'https://httpbin.org/status/404'
];
$mh = curl_multi_init();
$handles = [];
// 创建并添加每个请求
foreach ($urls as $i => $url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
// 执行并发请求
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
if ($mrc == CURLM_CALL_MULTI_PERFORM) continue;
if ($active > 0) {
curl_multi_select($mh, 1); // 最多等 1 秒
}
} while ($active > 0 || $mrc == CURLM_OK);
// 收集结果
$results = [];
while ($info = curl_multi_info_read($mh)) {
if ($info['result'] === CURLE_OK) {
$ch = $info['handle'];
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$body = curl_multi_getcontent($ch);
$results[] = [
'url' => $url,
'status' => $status,
'length' => strlen($body)
];
}
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
var_dump($results);
实用优化建议
- 限制并发数:一次性加太多句柄可能耗尽 socket 或触发服务端限流。可用队列分批处理(例如每次最多 10 个)
-
设置超时更精细:除了
CURLOPT_TIMEOUT,建议加上CURLOPT_CONNECTTIMEOUT_MS和CURLOPT_LOW_SPEED_LIMIT防止慢连接拖累整体 -
错误要检查:
$info['result']不为CURLE_OK时需记录错误码(如CURLE_COULDNT_CONNECT、CURLE_OPERATION_TIMEDOUT) -
避免内存泄漏:每个完成的句柄必须调用
curl_multi_remove_handle()+curl_close(),否则资源不释放
替代方案对比(简单说明)
如果项目允许升级,可考虑:
- Swoole HTTP Client:真正协程异步,语法简洁,性能更高,适合高并发场景
- Guzzle + RingPHP / HTTPlug:封装了 curl_multi,提供 Promise 接口,开发体验更好
- ReactPHP / Amp:事件驱动模型,适合构建长连接或流式服务
但若仅需轻量级批量请求,原生 curl_multi 仍是稳定、零依赖的选择。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










