curl_multi_select() 函数用于等待所有cURL多句柄中的活动连接。这个函数在并发处理多个cURL句柄时非常有用,可以避免CPU过度使用。
curl_multi_select ( CurlMultiHandle $multi_handle [, float $timeout = 1.0 ] ) : int
| 参数 | 描述 |
|---|---|
| multi_handle | 由 curl_multi_init() 返回的 cURL 多个句柄。 |
| timeout | 可选。等待响应的时间,以秒为单位。默认是1.0秒。 |
成功时返回描述符集合中准备就绪的描述符的数量,如果在任何描述符准备就绪前超时,则返回0,失败时返回-1。
// 初始化多个cURL句柄
$mh = curl_multi_init();
// 创建两个cURL资源
$ch1 = curl_init();
$ch2 = curl_init();
// 设置URL和相应的选项
curl_setopt_array($ch1, [
CURLOPT_URL => "http://www.example.com/",
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER => 1
]);
curl_setopt_array($ch2, [
CURLOPT_URL => "http://www.php.net/",
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER => 1
]);
// 增加两个句柄
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 执行批处理句柄
$active = null;
do {
$status = curl_multi_exec($mh, $active);
// 等待活动连接,避免CPU过度使用
if ($status > 0) {
// 有错误发生
break;
}
// 等待活动,超时时间为1秒
if (curl_multi_select($mh, 1.0) == -1) {
// 在select调用中发生错误
usleep(100000); // 等待100毫秒
}
} while ($active);
// 获取结果
$content1 = curl_multi_getcontent($ch1);
$content2 = curl_multi_getcontent($ch2);
// 关闭所有句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
echo "内容1长度: " . strlen($content1) . "\n";
echo "内容2长度: " . strlen($content2) . "\n";
function downloadMultipleUrls($urls, $timeout = 10) {
$mh = curl_multi_init();
$handles = [];
$results = [];
// 为每个URL创建cURL句柄
foreach ($urls as $key => $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP cURL)'
]);
curl_multi_add_handle($mh, $ch);
$handles[$key] = $ch;
$results[$key] = null;
}
// 执行所有请求
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
// 等待活动,避免CPU过度使用
if ($mrc == CURLM_OK) {
// 等待活动连接,超时时间500毫秒
if (curl_multi_select($mh, 0.5) == -1) {
usleep(10000); // 等待10毫秒
}
}
} while ($active && $mrc == CURLM_OK);
// 获取所有结果
foreach ($handles as $key => $ch) {
$results[$key] = [
'content' => curl_multi_getcontent($ch),
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
'error' => curl_error($ch)
];
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
return $results;
}
// 使用示例
$urls = [
'example' => 'http://www.example.com',
'php' => 'http://www.php.net',
'github' => 'http://www.github.com'
];
$results = downloadMultipleUrls($urls);
foreach ($results as $key => $result) {
echo "{$key}: HTTP {$result['http_code']}, 内容长度: " .
strlen($result['content']) . "\n";
}
function concurrentRequestsWithTimeout($urls, $timeout = 5) {
$mh = curl_multi_init();
$curlHandles = [];
foreach ($urls as $id => $url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_FOLLOWLOCATION => true
]);
curl_multi_add_handle($mh, $ch);
$curlHandles[$id] = $ch;
}
$startTime = time();
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
if ($mrc != CURLM_OK) {
break;
}
// 使用select等待活动,避免忙等待
$selectTimeout = 0.1; // 100毫秒
if (curl_multi_select($mh, $selectTimeout) === -1) {
usleep(10000); // 10毫秒
}
// 检查是否超时
if ((time() - $startTime) > $timeout) {
break;
}
} while ($active > 0);
$results = [];
foreach ($curlHandles as $id => $ch) {
$results[$id] = [
'content' => curl_multi_getcontent($ch),
'error' => curl_error($ch),
'http_code' => curl_getinfo($ch, CURLINFO_HTTP_CODE)
];
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
return $results;
}
curl_multi_select() 在失败时可能会立即返回0而不是等待指定的超时时间。在Windows上,这个函数在PHP 5.5.0之前不能正确工作。
curl_multi_select() 可以显著减少并发cURL请求时的CPU使用率,因为它会等待活动连接而不是持续轮询。
当 curl_multi_select() 返回-1时,通常意味着在select系统调用中发生了错误。在这种情况下,建议等待一小段时间(如100毫秒)后继续,以避免忙等待。