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 函数,并通过实际示例展示了其在高效处理多个请求中的用法。