PHP curl_multi_init 函数
最后修改日期:2025 年 4 月 11 日
PHP 的 curl_multi_init
函数创建一个多 cURL 句柄。它允许异步处理多个 cURL 句柄。这对于高效地进行并行 HTTP 请求非常有用。
基本定义
curl_multi_init
函数初始化一个新的多 cURL 句柄。它返回一个可以与其他 curl_multi 函数一起使用的资源。此句柄管理多个单独的 cURL 句柄。
语法:curl_multi_init(): CurlMultiHandle
。该函数不接受任何参数,并返回一个多 cURL 句柄。完成后务必使用 curl_multi_close()
进行清理。
基本并行请求
此示例演示了两个并行 HTTP GET 请求。
<?php declare(strict_types=1); $urls = [ "https://jsonplaceholder.typicode.com/posts/1", "https://jsonplaceholder.typicode.com/posts/2" ]; $mh = curl_multi_init(); $handles = []; foreach ($urls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, $ch); $handles[] = $ch; } $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); } while ($running > 0); foreach ($handles as $ch) { echo curl_multi_getcontent($ch) . "\n"; curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
此代码同时获取两个帖子。我们为每个 URL 创建单独的句柄并将它们添加到多句柄中。循环处理所有请求直至完成。最后,我们检索并输出响应。
使用回调处理响应
此示例展示了如何使用回调来处理完成的响应。
<?php declare(strict_types=1); $urls = [ "https://jsonplaceholder.typicode.com/users/1", "https://jsonplaceholder.typicode.com/users/2", "https://jsonplaceholder.typicode.com/users/3" ]; $mh = curl_multi_init(); $handles = []; foreach ($urls as $i => $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); curl_multi_add_handle($mh, $ch); $handles[$i] = $ch; } $processed = 0; do { curl_multi_exec($mh, $running); while ($info = curl_multi_info_read($mh)) { $ch = $info['handle']; $content = curl_multi_getcontent($ch); $index = array_search($ch, $handles, true); echo "Response $index: " . substr($content, 0, 50) . "...\n"; $processed++; curl_multi_remove_handle($mh, $ch); curl_close($ch); } if ($running) { curl_multi_select($mh); } } while ($running || $processed < count($urls)); curl_multi_close($mh);
我们使用 curl_multi_info_read 随着响应可用而处理它们。每个已完成的请求都会触发我们的回调逻辑。这种方法比等待所有请求完成更有效。我们跟踪已处理的请求以确保我们处理所有响应。
为并行请求设置超时
此示例演示了为并行请求设置单个超时。
<?php declare(strict_types=1); $urls = [ ["url" => "https://httpbin.org/delay/2", "timeout" => 3], ["url" => "https://httpbin.org/delay/5", "timeout" => 1] ]; $mh = curl_multi_init(); $handles = []; foreach ($urls as $i => $item) { $ch = curl_init($item['url']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, $item['timeout']); curl_multi_add_handle($mh, $ch); $handles[$i] = $ch; } $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); } while ($running > 0); foreach ($handles as $i => $ch) { $errno = curl_errno($ch); if ($errno === CURLE_OPERATION_TIMEDOUT) { echo "Request $i timed out\n"; } else { echo "Request $i completed: " . substr(curl_multi_getcontent($ch), 0, 30) . "...\n"; } curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
我们为每个请求设置了不同的超时。第二个请求将在 1 秒后超时,而第一个请求将成功完成。我们使用 curl_errno 检查超时错误。这种模式对于处理慢响应非常有用。
处理大量 URL
此示例展示了如何有效地处理具有并发控制的大量 URL。
<?php declare(strict_types=1); function fetchUrls(array $urls, int $concurrency = 5): array { $mh = curl_multi_init(); $results = []; $active = []; // Initialize first batch for ($i = 0; $i < min($concurrency, count($urls)); $i++) { $ch = curl_init($urls[$i]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, $ch); $active[$i] = true; } $nextUrl = $concurrency; $processed = 0; do { curl_multi_exec($mh, $running); curl_multi_select($mh); while ($info = curl_multi_info_read($mh)) { $ch = $info['handle']; $index = array_search($ch, $active, true); if ($index !== false) { $results[$index] = curl_multi_getcontent($ch); curl_multi_remove_handle($mh, $ch); curl_close($ch); $processed++; // Add next URL if available if ($nextUrl < count($urls)) { $ch = curl_init($urls[$nextUrl]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, $ch); $active[$nextUrl] = $ch; $nextUrl++; } } } } while ($running || $processed < count($urls)); curl_multi_close($mh); return $results; } $urls = array_fill(0, 20, "https://jsonplaceholder.typicode.com/posts/1"); $results = fetchUrls($urls, 5); echo "Fetched " . count($results) . " responses\n";
此实现分批处理 URL 以控制并发。我们维护一个活动连接池并替换已完成的连接。该函数按顺序返回所有响应。这种方法可以防止因过多的并发请求而导致服务器过载。
并行请求中的错误处理
此示例演示了并行请求的全面错误处理。
<?php declare(strict_types=1); $urls = [ "https://valid.example.com/api", "https://invalid.example.com/api", "https://timeout.example.com/api" ]; $mh = curl_multi_init(); $handles = []; foreach ($urls as $i => $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_FAILONERROR, true); curl_multi_add_handle($mh, $ch); $handles[$i] = [ 'handle' => $ch, 'url' => $url ]; } $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); } while ($running > 0); foreach ($handles as $i => $item) { $ch = $item['handle']; $errno = curl_errno($ch); if ($errno) { echo "Request $i failed (" . $item['url'] . "): " . curl_error($ch) . "\n"; } else { $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode >= 200 && $httpCode < 300) { echo "Request $i succeeded: " . substr(curl_multi_getcontent($ch), 0, 50) . "...\n"; } else { echo "Request $i returned HTTP $httpCode\n"; } } curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
我们为每个请求实现了健壮的错误检查。代码检查 cURL 错误、HTTP 状态码和超时。每次失败都会记录有关出错内容的详细信息。成功响应会照常处理。
最佳实践
- 并发控制:限制并发连接。
- 错误处理:同时检查 cURL 和 HTTP 错误。
- 资源清理:始终删除和关闭句柄。
- 超时设置:为每个请求设置合理的超时。
- 内存管理:随到随处理响应。
来源
本教程介绍了 PHP curl_multi_init
函数,并通过实际示例展示了并行请求处理。这些示例演示了各种实际场景和最佳实践。