PHP curl_multi_exec 函数
最后修改日期:2025 年 4 月 11 日
PHP curl_multi_exec 函数并行执行多个 cURL 句柄。它用于同时执行多个 HTTP 请求,在从多个源获取数据时提高性能。
基本定义
curl_multi_exec 函数运行当前 cURL 多句柄的子连接。它异步处理每个句柄,实现并行请求。该函数返回一个在 cURL.h 中定义的 cURL 代码。
语法:curl_multi_exec(CurlMultiHandle $multi_handle, int &$still_running): int。$still_running 参数用于填充仍运行的句柄数量。该函数应重复调用,直到所有句柄完成。
基本并行请求
此示例演示了向不同 URL 发送两个并行 GET 请求。
<?php
declare(strict_types=1);
// Create multiple cURL handles
$ch1 = curl_init();
$ch2 = curl_init();
curl_setopt($ch1, CURLOPT_URL, "https://jsonplaceholder.typicode.com/posts/1");
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_URL, "https://jsonplaceholder.typicode.com/comments/1");
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
// Create the multi cURL handle
$mh = curl_multi_init();
// Add the handles
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// Execute the handles
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
// Get the responses
$response1 = curl_multi_getcontent($ch1);
$response2 = curl_multi_getcontent($ch2);
// Close the handles
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
echo "Post 1: " . $response1 . "\n\n";
echo "Comment 1: " . $response2;
此代码为不同的 API 端点创建了两个 cURL 句柄。我们将它们添加到多句柄并并行执行它们。循环将一直持续到所有请求完成。最后,我们检索并显示响应。
处理多个响应
此示例展示了如何正确处理多个并行请求的响应。
<?php
declare(strict_types=1);
$urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/comments/1",
"https://jsonplaceholder.typicode.com/albums/1"
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$handles[$i] = curl_init();
curl_setopt($handles[$i], CURLOPT_URL, $url);
curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $handles[$i]);
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
$responses = [];
foreach ($handles as $i => $handle) {
$responses[$i] = curl_multi_getcontent($handle);
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
}
curl_multi_close($mh);
foreach ($responses as $i => $response) {
echo "Response $i: " . substr($response, 0, 100) . "...\n\n";
}
我们从 URL 数组创建多个 cURL 句柄。并行执行后,我们将所有响应收集到一个数组中。该示例演示了正确的资源清理,并展示了如何有效地处理多个响应。
并行请求中的错误处理
此示例演示了并行 cURL 请求的正确错误处理。
<?php
declare(strict_types=1);
$urls = [
"https://valid.url/api",
"https://invalid.url/api",
"https://another.valid.url/api"
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$handles[$i] = curl_init();
curl_setopt($handles[$i], CURLOPT_URL, $url);
curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, true);
curl_setopt($handles[$i], CURLOPT_TIMEOUT, 10);
curl_multi_add_handle($mh, $handles[$i]);
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
$results = [];
foreach ($handles as $i => $handle) {
$error = curl_error($handle);
if ($error) {
$results[$i] = "Error for URL $i: " . $error;
} else {
$results[$i] = "Success for URL $i: " .
substr(curl_multi_getcontent($handle), 0, 50) . "...";
}
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
}
curl_multi_close($mh);
print_r($results);
此示例包括对每个请求的错误检查。我们在执行后检查 cURL 错误并将适当的消息存储起来。超时选项可防止在无响应服务器上挂起。结果会连同成功/错误状态一起收集。
控制并发
此示例展示了如何使用队列控制并行请求的数量。
<?php
declare(strict_types=1);
$urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2",
"https://jsonplaceholder.typicode.com/posts/3",
"https://jsonplaceholder.typicode.com/posts/4",
"https://jsonplaceholder.typicode.com/posts/5"
];
$maxConcurrent = 2; // Maximum parallel requests
$mh = curl_multi_init();
$activeHandles = [];
$allResponses = [];
$currentIndex = 0;
while ($currentIndex < count($urls) || count($activeHandles) > 0) {
// Add new requests if under limit
while (count($activeHandles) < $maxConcurrent && $currentIndex < count($urls)) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $urls[$currentIndex]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$activeHandles[$currentIndex] = $ch;
$currentIndex++;
}
// Execute the current batch
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
// Process completed requests
foreach ($activeHandles as $i => $ch) {
$info = curl_getinfo($ch);
if ($info['http_code'] == 200) {
$allResponses[$i] = substr(curl_multi_getcontent($ch), 0, 50) . "...";
} else {
$allResponses[$i] = "Error for URL $i";
}
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
unset($activeHandles[$i]);
}
}
curl_multi_close($mh);
print_r($allResponses);
这个高级示例实现了一个队列系统来控制并发。我们将 URL 分批(每次 2 个)处理,以保持最佳性能而不使服务器过载。在开始新的请求之前,会处理并移除已完成的请求。
处理已完成的响应
此示例演示了立即处理已完成的响应。
<?php
declare(strict_types=1);
$urls = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/comments/1",
"https://jsonplaceholder.typicode.com/albums/1",
"https://jsonplaceholder.typicode.com/photos/1",
"https://jsonplaceholder.typicode.com/todos/1"
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$handles[$i] = curl_init();
curl_setopt($handles[$i], CURLOPT_URL, $url);
curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $handles[$i]);
}
$completed = 0;
$total = count($urls);
do {
$status = curl_multi_exec($mh, $running);
if ($status === CURLM_OK) {
// Check for completed requests
while ($info = curl_multi_info_read($mh)) {
$handle = $info['handle'];
$index = array_search($handle, $handles, true);
if ($info['result'] === CURLE_OK) {
$response = curl_multi_getcontent($handle);
echo "Completed $index: " . substr($response, 0, 50) . "...\n";
} else {
echo "Failed $index: " . curl_error($handle) . "\n";
}
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
$completed++;
}
}
if ($running) {
curl_multi_select($mh, 0.1);
}
} while ($running > 0 || $completed < $total);
curl_multi_close($mh);
此示例在响应可用时立即处理它们,而不是等待所有请求完成。我们使用 curl_multi_info_read 来检测已完成的请求。此方法适用于处理大量具有不同响应时间的请求。
最佳实践
- 限制并发:控制并行请求以避免服务器过载。
- 错误处理:检查每个请求的状态和错误。
- 资源清理:始终正确移除和关闭句柄。
- 超时:为每个句柄设置 CURLOPT_TIMEOUT。
- 内存管理:为大批量处理即时完成的响应。
来源
本教程涵盖了 PHP curl_multi_exec 函数,并提供了实际示例,展示了并行请求执行和响应处理。