PHP curl_multi_select 函数
最后修改日期:2025 年 4 月 11 日
PHP curl_multi_select
函数等待任何 cURL multi handle 上的活动。它与 curl_multi_exec
一起使用,以高效处理多个 cURL 请求。此函数有助于避免忙等待。
基本定义
curl_multi_select
函数会一直等待,直到任何 cURL multi handle 上有活动。它返回描述符集中包含的描述符数量,失败时返回 -1。
语法:curl_multi_select(CurlMultiHandle $multi_handle, float $timeout = 1.0): int
。timeout 参数指定等待的秒数。timeout 为 0 表示立即返回。
基本多请求处理
本示例演示了 curl_multi_select 与多个 URL 的基本用法。
<?php declare(strict_types=1); $urls = [ "https://jsonplaceholder.typicode.com/posts/1", "https://jsonplaceholder.typicode.com/posts/2", "https://jsonplaceholder.typicode.com/posts/3" ]; $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; } $active = null; do { $status = curl_multi_exec($mh, $active); if ($status > 0) { break; // Error occurred } curl_multi_select($mh); // Wait for activity } while ($active); foreach ($handles as $ch) { echo curl_multi_getcontent($ch) . "\n"; curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
此代码同时获取三个帖子。我们创建单独的句柄,将它们添加到 multi handle,然后进行处理。select 调用可防止在执行期间进行 CPU 密集型的忙等待。
自定义超时处理
本示例展示了如何使用自定义超时与 curl_multi_select。
<?php declare(strict_types=1); $urls = [ "https://httpbin.org/delay/1", "https://httpbin.org/delay/2", "https://httpbin.org/delay/3" ]; $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; } $active = null; $start = microtime(true); do { $status = curl_multi_exec($mh, $active); if ($status > 0) { break; } // Wait for up to 500ms for activity $select = curl_multi_select($mh, 0.5); if ($select === -1) { // Error occurred in select usleep(100000); // Sleep briefly to prevent CPU overload } } while ($active && (microtime(true) - $start < 5)); // Max 5 seconds foreach ($handles as $ch) { echo "Response length: " . strlen(curl_multi_getcontent($ch)) . "\n"; curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
我们使用 500ms 的超时时间,并实现 5 秒的最大执行时间。代码通过短暂休眠来处理 select 返回的 -1 值。此方法可以更好地控制执行流程。
处理大量请求
本示例演示了如何高效处理大量请求。
<?php declare(strict_types=1); // Generate 10 test URLs $urls = array_map(function($i) { return "https://jsonplaceholder.typicode.com/posts/" . ($i + 1); }, range(0, 9)); $mh = curl_multi_init(); $handles = []; // Add all handles at once foreach ($urls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, $ch); $handles[$url] = $ch; } $active = null; $processed = 0; do { $status = curl_multi_exec($mh, $active); if ($status === CURLM_OK) { // Wait for activity with 100ms timeout $select = curl_multi_select($mh, 0.1); if ($select > 0) { // Process completed requests while ($info = curl_multi_info_read($mh)) { $ch = $info['handle']; $url = array_search($ch, $handles, true); if ($info['result'] === CURLE_OK) { echo "Completed: $url\n"; } else { echo "Error: $url - " . curl_error($ch) . "\n"; } curl_multi_remove_handle($mh, $ch); curl_close($ch); $processed++; } } } } while ($active || $processed < count($urls)); curl_multi_close($mh);
此代码高效处理 10 个请求。我们使用 curl_multi_info_read 来单独检查已完成的请求。select 超时设置为 100ms 以实现响应式处理。已完成的请求在检测到时会立即得到处理。
错误处理和超时
本示例展示了 curl_multi_select 的稳健错误处理。
<?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 $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 3); // Individual timeout curl_multi_add_handle($mh, $ch); $handles[] = $ch; } $active = null; $start = time(); do { $status = curl_multi_exec($mh, $active); if ($status > CURLM_OK) { echo "Multi error: " . curl_multi_strerror($status) . "\n"; break; } $select = curl_multi_select($mh, 0.5); if ($select === -1) { echo "Select error occurred\n"; usleep(100000); } // Global timeout check if (time() - $start > 5) { echo "Global timeout reached\n"; break; } } while ($active); foreach ($handles as $ch) { $info = curl_getinfo($ch); if (curl_errno($ch)) { echo "Error: " . curl_error($ch) . "\n"; } else { echo "HTTP " . $info['http_code'] . " - " . $info['url'] . "\n"; } curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
我们实现了多层错误处理。每个请求都有 3 秒的超时时间,整个操作有 5 秒的全局超时时间。我们同时检查 multi 错误和 select 错误,并提供适当的反馈。
高级性能优化
本示例演示了性能优化技术。
<?php declare(strict_types=1); $urls = [ "https://api.example.com/resource1", "https://api.example.com/resource2", "https://api.example.com/resource3" ]; $mh = curl_multi_init(); $handles = []; // Configure multi handle for better performance curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, 10); curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); foreach ($urls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // Enable compression curl_setopt($ch, CURLOPT_TCP_NODELAY, true); // Disable Nagle's algorithm curl_multi_add_handle($mh, $ch); $handles[] = $ch; } $active = null; $processed = 0; $results = []; do { $status = curl_multi_exec($mh, $active); if ($status === CURLM_OK) { // Use 0 timeout for non-blocking check $select = curl_multi_select($mh, 0); if ($select > 0) { while ($info = curl_multi_info_read($mh)) { $ch = $info['handle']; $results[] = [ 'content' => curl_multi_getcontent($ch), 'info' => curl_getinfo($ch) ]; curl_multi_remove_handle($mh, $ch); curl_close($ch); $processed++; } } else { // Do other work here if no immediate activity usleep(10000); // 10ms delay } } } while ($active || $processed < count($urls)); curl_multi_close($mh); // Process results foreach ($results as $result) { echo "URL: " . $result['info']['url'] . "\n"; echo "Time: " . $result['info']['total_time'] . "s\n\n"; }
此优化实现使用了 HTTP/2 多路复用、gzip 压缩和 TCP 优化。我们使用非阻塞 select 并设置 0 超时时间来检查即时活动。代码可以在等待时执行其他工作。
最佳实践
- 超时处理:始终设置合理的超时时间。
- 错误检查:验证 curl_multi_select 的返回值。
- 资源清理:移除并关闭所有句柄。
- 性能:尽可能使用 HTTP/2 多路复用。
- CPU 使用率:通过正确使用 select 来避免忙等待。
来源
本教程涵盖了 PHP curl_multi_select
函数,并通过实际示例展示了其在高效处理多个请求中的用法。