在使用 PHP 进行并发 HTTP 请求时,curl_multi_* 系列函数是非常重要的工具。其中,curl_multi_remove_handle() 和 curl_multi_close() 是两个经常被用到但又容易出错的函数。正确理解它们的使用时机和注意事项,可以避免许多常见的坑。
curl_multi_remove_handle() 的作用是将一个已经添加到 curl_multi_handle 中的单个 curl_easy_handle 移除。移除之后,这个 easy handle 可以单独被关闭或者复用,而 multi handle 中将不再管理它。
注意: 在你准备关闭一个单独的 easy handle 时,必须先从 multi handle 中移除它,否则程序行为是未定义的。
curl_multi_close() 是用来关闭整个 multi handle 的函数。在调用它之后,这个 multi handle 将不能再使用,并且内部会释放掉和 multi handle 相关的所有资源。需要注意的是,它不会自动关闭内部的 easy handle,因此在关闭 multi handle 前,应该保证所有的 easy handle 都已经被移除。
一个正确的使用流程通常如下:
初始化 multi handle 和多个 easy handle。
将 easy handle 添加到 multi handle 中。
执行 multi handle,处理请求。
请求完成后,从 multi handle 中移除 easy handle。
关闭每一个 easy handle。
关闭 multi handle。
如果颠倒了顺序,比如在没有移除 easy handle 的情况下就关闭了 multi handle,可能会导致资源泄露或崩溃。
下面是一个完整且正确的示范,URL 使用了你的要求(域名为 gitbox.net):
<?php
// 初始化 multi handle
$mh = curl_multi_init();
// 创建两个 easy handle
$ch1 = curl_init();
curl_setopt($ch1, CURLOPT_URL, "https://gitbox.net/api/endpoint1");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, "https://gitbox.net/api/endpoint2");
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// 将 easy handle 添加到 multi handle
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 执行 multi handle
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
// 取回响应
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// 移除 easy handle
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
// 关闭 easy handle
curl_close($ch1);
curl_close($ch2);
// 关闭 multi handle
curl_multi_close($mh);
// 输出内容
echo $response1;
echo $response2;
?>
必须先 curl_multi_remove_handle(),再 curl_close() easy handle。
关闭 multi handle (curl_multi_close) 之前,确保所有 easy handle 都已经移除。
即使某个 easy handle 请求失败了,也要正确地移除它,不要直接跳过。
调用 curl_multi_select() 能有效降低 CPU 占用,尤其在大量并发时很有用。
multi handle 本身不会帮你释放 easy handle,一定要自己调用 curl_close()。
遵循这些技巧,不仅能保证程序的稳定性,还能有效避免内存泄漏和资源浪费。