curl_multi_info_read() 函数用于从cURL多句柄中读取已完成传输的信息。这个函数是并行请求处理中的关键函数,它允许程序获取每个请求的完成状态、结果代码和对应的句柄。
array|false curl_multi_info_read ( resource $mh [, int &$msgs_in_queue = null ] )
| 参数 | 描述 | 类型 | 必需 |
|---|---|---|---|
| mh | 由 curl_multi_init() 返回的cURL多句柄 |
resource | 是 |
| msgs_in_queue | 引用参数,返回仍然在信息队列中的消息数量 | int | 否 |
返回一个关联数组,包含已完成请求的信息,或者在没有更多信息时返回 FALSE。
返回数组包含以下键:
msg - 常量 CURLMSG_DONE,表示传输已完成result - cURL错误代码,CURLE_OK 表示成功handle - 完成传输的cURL句柄资源array(
'msg' => CURLMSG_DONE, // 固定值,表示传输完成
'result' => CURLE_OK, // cURL错误代码,0表示成功
'handle' => resource // 对应的cURL句柄资源
)
通过 result 字段可以判断请求是否成功:
CURLE_OK (0) - 请求成功完成@php
// 创建多句柄
$mh = curl_multi_init();
// 创建多个cURL句柄
$urls = [
'https://httpbin.org/delay/1',
'https://httpbin.org/delay/2',
'https://httpbin.org/delay/3'
];
$handles = [];
foreach ($urls as $i => $url) {
$handles[$i] = curl_init($url);
curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $handles[$i]);
}
// 执行并行请求
$active = null;
do {
$status = curl_multi_exec($mh, $active);
if ($active) {
curl_multi_select($mh, 0.1);
}
} while ($active > 0);
echo "所有请求执行完成,开始读取完成信息...\n\n";
// 读取所有完成信息
$completedCount = 0;
$msgsInQueue = null;
while ($info = curl_multi_info_read($mh, $msgsInQueue)) {
$completedCount++;
echo "=== 完成信息 #{$completedCount} ===\n";
echo "消息类型: {$info['msg']} " . ($info['msg'] === CURLMSG_DONE ? '(CURLMSG_DONE)' : '') . "\n";
echo "结果代码: {$info['result']} " . ($info['result'] === CURLE_OK ? '(CURLE_OK - 成功)' : '(失败)') . "\n";
// 查找对应的URL
$handle = $info['handle'];
$index = array_search($handle, $handles, true);
$url = $index !== false ? $urls[$index] : '未知URL';
echo "对应URL: {$url}\n";
// 获取更多信息
$content = curl_multi_getcontent($handle);
$curlInfo = curl_getinfo($handle);
echo "HTTP状态码: {$curlInfo['http_code']}\n";
echo "总耗时: " . round($curlInfo['total_time'], 3) . " 秒\n";
echo "内容长度: " . strlen($content) . " 字节\n";
if ($info['result'] !== CURLE_OK) {
$error = curl_error($handle);
echo "错误信息: {$error}\n";
}
echo "剩余队列消息: {$msgsInQueue}\n\n";
// 清理资源
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
}
echo "总共读取了 {$completedCount} 条完成信息\n";
curl_multi_close($mh);
@endphp
@php
class RealTimeInfoProcessor {
private $multiHandle;
private $handles = [];
private $results = [];
public function __construct() {
$this->multiHandle = curl_multi_init();
}
public function addRequest($url, $id = null) {
if ($id === null) {
$id = uniqid('req_');
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30
]);
$this->handles[$id] = $ch;
curl_multi_add_handle($this->multiHandle, $ch);
return $id;
}
public function execute() {
echo "开始执行并行请求...\n";
$active = null;
$processedCount = 0;
do {
// 执行多句柄
$status = curl_multi_exec($this->multiHandle, $active);
// 实时处理完成信息
$this->processCompletedInfos();
// 显示进度
$remaining = count($this->handles);
if ($remaining > 0) {
echo "进度: {$processedCount} 完成, {$remaining} 进行中, 活动句柄: {$active}\n";
}
// 等待活动
if ($active > 0) {
curl_multi_select($this->multiHandle, 0.1);
}
} while ($active > 0 || !empty($this->handles));
echo "所有请求处理完成!\n";
return $this->results;
}
private function processCompletedInfos() {
$msgsInQueue = null;
// 循环读取所有可用的完成信息
while ($info = curl_multi_info_read($this->multiHandle, $msgsInQueue)) {
$this->processSingleInfo($info);
}
}
private function processSingleInfo($info) {
$handle = $info['handle'];
$id = array_search($handle, $this->handles, true);
if ($id === false) {
echo "警告: 找不到对应的句柄ID\n";
return;
}
// 获取请求结果
$content = curl_multi_getcontent($handle);
$curlInfo = curl_getinfo($handle);
$error = curl_error($handle);
$result = [
'success' => ($info['result'] === CURLE_OK),
'result_code' => $info['result'],
'content' => $content,
'info' => $curlInfo,
'error' => $error,
'processed_at' => microtime(true)
];
// 根据结果代码进行详细处理
$this->handleByResultCode($id, $result, $info['result']);
// 存储结果
$this->results[$id] = $result;
// 清理资源
curl_multi_remove_handle($this->multiHandle, $handle);
curl_close($handle);
unset($this->handles[$id]);
$status = $result['success'] ? '成功' : '失败';
echo "→ 请求 {$id} 处理完成: {$status} (" . round($curlInfo['total_time'], 2) . "秒)\n";
}
private function handleByResultCode($id, &$result, $resultCode) {
$result['result_description'] = $this->getResultDescription($resultCode);
switch ($resultCode) {
case CURLE_OK:
// 成功请求
$result['action'] = 'process_content';
break;
case CURLE_OPERATION_TIMEDOUT:
// 超时请求
$result['action'] = 'retry_or_fail';
$result['suggestion'] = '增加超时时间或检查网络连接';
break;
case CURLE_COULDNT_RESOLVE_HOST:
// DNS解析失败
$result['action'] = 'check_url';
$result['suggestion'] = '检查URL是否正确,DNS设置';
break;
case CURLE_COULDNT_CONNECT:
// 连接失败
$result['action'] = 'retry_later';
$result['suggestion'] = '服务器可能暂时不可用,稍后重试';
break;
default:
$result['action'] = 'investigate';
$result['suggestion'] = '查看cURL文档了解错误代码含义';
}
}
private function getResultDescription($resultCode) {
$descriptions = [
CURLE_OK => '操作成功完成',
CURLE_OPERATION_TIMEDOUT => '操作超时',
CURLE_COULDNT_RESOLVE_HOST => '无法解析主机',
CURLE_COULDNT_CONNECT => '无法连接到服务器',
CURLE_SSL_CONNECT_ERROR => 'SSL连接错误',
CURLE_GOT_NOTHING => '服务器未返回任何数据'
];
return $descriptions[$resultCode] ?? "未知错误代码: {$resultCode}";
}
public function getStats() {
$stats = [
'total_requests' => count($this->results),
'successful' => 0,
'failed' => 0,
'total_time' => 0
];
foreach ($this->results as $result) {
if ($result['success']) {
$stats['successful']++;
} else {
$stats['failed']++;
}
$stats['total_time'] += $result['info']['total_time'];
}
return $stats;
}
public function close() {
foreach ($this->handles as $handle) {
if (is_resource($handle)) {
curl_multi_remove_handle($this->multiHandle, $handle);
curl_close($handle);
}
}
if (is_resource($this->multiHandle)) {
curl_multi_close($this->multiHandle);
}
$this->handles = [];
$this->results = [];
}
public function __destruct() {
$this->close();
}
}
// 使用实时信息处理器
$processor = new RealTimeInfoProcessor();
// 添加多个请求(包含一些可能失败的URL用于测试)
$requests = [
'fast' => 'https://httpbin.org/delay/1',
'medium' => 'https://httpbin.org/delay/2',
'slow' => 'https://httpbin.org/delay/3',
'timeout' => 'https://httpbin.org/delay/5', // 可能超时
'invalid' => 'https://invalid-url-test-12345.com' // 会失败
];
foreach ($requests as $id => $url) {
$processor->addRequest($url, $id);
}
// 执行并实时处理
$results = $processor->execute();
// 显示统计信息
$stats = $processor->getStats();
echo "\n执行统计:\n";
echo "总请求数: {$stats['total_requests']}\n";
echo "成功: {$stats['successful']}\n";
echo "失败: {$stats['failed']}\n";
echo "成功率: " . round(($stats['successful'] / $stats['total_requests']) * 100, 1) . "%\n";
echo "总耗时: " . round($stats['total_time'], 2) . " 秒\n";
// 显示详细结果
echo "\n详细结果:\n";
foreach ($results as $id => $result) {
$status = $result['success'] ? '✓' : '✗';
$code = $result['result_code'];
$desc = $result['result_description'];
echo "{$status} {$id}: 代码{$code} - {$desc}\n";
if (!$result['success']) {
echo " 建议: {$result['suggestion']}\n";
}
}
$processor->close();
@endphp
@php
class RetryableMultiRequest {
private $multiHandle;
private $requests = [];
private $maxRetries;
private $completed = [];
public function __construct($maxRetries = 3) {
$this->multiHandle = curl_multi_init();
$this->maxRetries = $maxRetries;
}
public function addRequest($url, $id = null) {
if ($id === null) {
$id = uniqid('req_');
}
$this->requests[$id] = [
'url' => $url,
'handle' => null,
'retries' => 0,
'completed' => false,
'last_result' => null
];
$this->createHandle($id);
return $id;
}
private function createHandle($id) {
$request = &$this->requests[$id];
// 清理旧的句柄(如果存在)
if ($request['handle'] && is_resource($request['handle'])) {
curl_multi_remove_handle($this->multiHandle, $request['handle']);
curl_close($request['handle']);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $request['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5
]);
$request['handle'] = $ch;
$request['retries']++;
curl_multi_add_handle($this->multiHandle, $ch);
echo "创建句柄: {$id} (尝试: {$request['retries']}/{$this->maxRetries})\n";
}
public function execute() {
echo "开始执行带重试机制的并行请求...\n";
echo "最大重试次数: {$this->maxRetries}\n\n";
$startTime = microtime(true);
do {
// 执行多句柄
$active = null;
do {
curl_multi_exec($this->multiHandle, $active);
if ($active > 0) {
curl_multi_select($this->multiHandle, 0.1);
}
} while ($active > 0);
// 处理所有完成信息
$this->processCompletedRequests();
// 重试失败的请求
$retryCount = $this->retryFailedRequests();
if ($retryCount > 0) {
echo "正在进行第 {$retryCount} 轮重试...\n";
}
} while ($retryCount > 0 && !empty($this->requests));
$totalTime = microtime(true) - $startTime;
echo "\n所有请求处理完成!总耗时: " . round($totalTime, 2) . " 秒\n";
return $this->completed;
}
private function processCompletedRequests() {
$msgsInQueue = null;
while ($info = curl_multi_info_read($this->multiHandle, $msgsInQueue)) {
$handle = $info['handle'];
$id = $this->findRequestId($handle);
if ($id !== null) {
$this->handleRequestCompletion($id, $handle, $info);
}
}
}
private function findRequestId($handle) {
foreach ($this->requests as $id => $request) {
if ($request['handle'] === $handle) {
return $id;
}
}
return null;
}
private function handleRequestCompletion($id, $handle, $info) {
$request = &$this->requests[$id];
$content = curl_multi_getcontent($handle);
$curlInfo = curl_getinfo($handle);
$error = curl_error($handle);
$result = [
'success' => ($info['result'] === CURLE_OK),
'result_code' => $info['result'],
'content' => $content,
'info' => $curlInfo,
'error' => $error,
'retries' => $request['retries'] - 1,
'final_attempt' => ($request['retries'] >= $this->maxRetries)
];
$request['last_result'] = $result;
// 从多句柄中移除当前句柄
curl_multi_remove_handle($this->multiHandle, $handle);
curl_close($handle);
$status = $result['success'] ? '成功' : '失败';
echo "请求 {$id}: {$status} (尝试: {$request['retries']}, 代码: {$info['result']})\n";
// 如果成功或达到最大重试次数,标记为完成
if ($result['success'] || $request['retries'] >= $this->maxRetries) {
$this->completed[$id] = $result;
unset($this->requests[$id]);
}
}
private function retryFailedRequests() {
$retryCount = 0;
$requestsToRetry = [];
// 收集需要重试的请求
foreach ($this->requests as $id => $request) {
if (!$request['completed'] && $request['retries'] < $this->maxRetries) {
$requestsToRetry[] = $id;
}
}
// 重试请求
foreach ($requestsToRetry as $id) {
$this->createHandle($id);
$retryCount++;
}
return $retryCount;
}
public function getStats() {
$stats = [
'total' => count($this->completed),
'successful' => 0,
'failed' => 0,
'total_retries' => 0
];
foreach ($this->completed as $result) {
if ($result['success']) {
$stats['successful']++;
} else {
$stats['failed']++;
}
$stats['total_retries'] += $result['retries'];
}
return $stats;
}
public function close() {
foreach ($this->requests as $request) {
if ($request['handle'] && is_resource($request['handle'])) {
curl_multi_remove_handle($this->multiHandle, $request['handle']);
curl_close($request['handle']);
}
}
if (is_resource($this->multiHandle)) {
curl_multi_close($this->multiHandle);
}
$this->requests = [];
$this->completed = [];
}
public function __destruct() {
$this->close();
}
}
// 使用带重试机制的请求器
$requester = new RetryableMultiRequest(2); // 最大重试2次
// 添加请求(包含一些可能失败的URL)
$urls = [
'reliable' => 'https://httpbin.org/delay/1',
'slow' => 'https://httpbin.org/delay/3',
'unreliable' => 'https://httpbin.org/delay/5', // 可能超时
'invalid' => 'https://invalid-domain-12345.net' // 会失败
];
foreach ($urls as $id => $url) {
$requester->addRequest($url, $id);
}
$results = $requester->execute();
// 显示统计信息
$stats = $requester->getStats();
echo "\n最终统计:\n";
echo "总请求: {$stats['total']}\n";
echo "成功: {$stats['successful']}\n";
echo "失败: {$stats['failed']}\n";
echo "总重试次数: {$stats['total_retries']}\n";
// 显示每个请求的详细结果
echo "\n详细结果:\n";
foreach ($results as $id => $result) {
$status = $result['success'] ? '✓' : '✗';
$attempts = $result['retries'] + 1;
$final = $result['final_attempt'] ? ' (最终尝试)' : '';
echo "{$status} {$id}: 尝试{$attempts}次";
if ($result['success']) {
echo ", 内容长度: " . strlen($result['content']) . " 字节";
} else {
echo ", 错误: {$result['error']}";
}
echo "{$final}\n";
}
$requester->close();
@endphp
@php
class AdvancedMultiMonitor {
private $multiHandle;
private $requests = [];
private $results = [];
private $startTime;
private $monitoringData = [];
public function __construct() {
$this->multiHandle = curl_multi_init();
$this->startTime = microtime(true);
}
public function addRequest($url, $id = null, $metadata = []) {
if ($id === null) {
$id = uniqid('req_');
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HEADER => true, // 包含头部信息用于分析
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => function($resource, $download_size, $downloaded, $upload_size, $uploaded) use ($id) {
$this->recordProgress($id, $download_size, $downloaded);
return 0;
}
]);
$this->requests[$id] = [
'handle' => $ch,
'url' => $url,
'metadata' => $metadata,
'start_time' => microtime(true),
'progress' => []
];
curl_multi_add_handle($this->multiHandle, $ch);
return $id;
}
private function recordProgress($id, $totalSize, $downloaded) {
if ($totalSize > 0) {
$progress = round(($downloaded / $totalSize) * 100, 1);
$this->requests[$id]['progress'][] = [
'time' => microtime(true) - $this->startTime,
'progress' => $progress,
'downloaded' => $downloaded,
'total_size' => $totalSize
];
}
}
public function execute() {
echo "开始高级监控执行...\n";
$active = null;
$lastMonitorTime = 0;
do {
// 执行多句柄
$status = curl_multi_exec($this->multiHandle, $active);
// 处理完成信息
$this->monitorCompletedRequests();
// 定期输出监控信息(每秒一次)
$currentTime = microtime(true);
if ($currentTime - $lastMonitorTime >= 1.0) {
$this->outputMonitoringInfo();
$lastMonitorTime = $currentTime;
}
// 等待活动
if ($active > 0) {
curl_multi_select($this->multiHandle, 0.1);
}
} while ($active > 0 || !empty($this->requests));
// 最终处理
$this->monitorCompletedRequests(true);
$totalTime = microtime(true) - $this->startTime;
echo "\n执行完成!总耗时: " . round($totalTime, 2) . " 秒\n";
return $this->generateReport();
}
private function monitorCompletedRequests($final = false) {
$msgsInQueue = null;
while ($info = curl_multi_info_read($this->multiHandle, $msgsInQueue)) {
$this->processRequestCompletion($info);
}
}
private function processRequestCompletion($info) {
$handle = $info['handle'];
$id = $this->findRequestId($handle);
if ($id === null) {
return;
}
$request = $this->requests[$id];
$completionTime = microtime(true);
$duration = $completionTime - $request['start_time'];
// 获取完整响应(包含头部)
$fullResponse = curl_multi_getcontent($handle);
$curlInfo = curl_getinfo($handle);
$error = curl_error($handle);
// 分离头部和主体
$headerSize = $curlInfo['header_size'];
$headers = substr($fullResponse, 0, $headerSize);
$body = substr($fullResponse, $headerSize);
$result = [
'success' => ($info['result'] === CURLE_OK),
'result_code' => $info['result'],
'headers' => $headers,
'body' => $body,
'info' => $curlInfo,
'error' => $error,
'duration' => $duration,
'progress_data' => $request['progress'],
'metadata' => $request['metadata'],
'completed_at' => $completionTime
];
// 分析性能数据
$this->analyzePerformance($id, $result);
$this->results[$id] = $result;
// 清理资源
curl_multi_remove_handle($this->multiHandle, $handle);
curl_close($handle);
unset($this->requests[$id]);
$this->recordCompletion($id, $result);
}
private function findRequestId($handle) {
foreach ($this->requests as $id => $request) {
if ($request['handle'] === $handle) {
return $id;
}
}
return null;
}
private function analyzePerformance($id, &$result) {
$progress = $result['progress_data'];
if (count($progress) > 1) {
// 计算平均下载速度
$first = $progress[0];
$last = end($progress);
$timeDiff = $last['time'] - $first['time'];
$dataDiff = $last['downloaded'] - $first['downloaded'];
if ($timeDiff > 0) {
$result['avg_speed_kbps'] = round(($dataDiff / $timeDiff) / 1024, 2);
}
// 检测下载阶段
$result['download_phases'] = $this->detectDownloadPhases($progress);
}
}
private function detectDownloadPhases($progress) {
if (count($progress) < 3) {
return ['数据不足分析阶段'];
}
$phases = [];
$lastProgress = 0;
foreach ($progress as $point) {
$currentProgress = $point['progress'];
if ($currentProgress - $lastProgress > 20) {
$phases[] = "阶段: {$lastProgress}% → {$currentProgress}%";
$lastProgress = $currentProgress;
}
}
return $phases ?: ['稳定下载'];
}
private function outputMonitoringInfo() {
$elapsed = microtime(true) - $this->startTime;
$completed = count($this->results);
$remaining = count($this->requests);
$active = 0;
// 计算活动请求数(粗略估计)
foreach ($this->requests as $request) {
if (!empty($request['progress'])) {
$active++;
}
}
echo sprintf(
"[%.1fs] 完成: %d, 进行中: %d, 活动: %d, 总进度: %.1f%%\n",
$elapsed, $completed, $remaining, $active,
$completed > 0 ? ($completed / ($completed + $remaining)) * 100 : 0
);
// 显示最近完成的请求
$recentResults = array_slice($this->results, -3);
foreach ($recentResults as $id => $result) {
$status = $result['success'] ? '✓' : '✗';
$speed = isset($result['avg_speed_kbps']) ? $result['avg_speed_kbps'] . ' KB/s' : 'N/A';
echo " {$status} {$id}: " . round($result['duration'], 2) . "s, {$speed}\n";
}
}
private function recordCompletion($id, $result) {
$this->monitoringData['completions'][] = [
'id' => $id,
'time' => microtime(true) - $this->startTime,
'success' => $result['success'],
'duration' => $result['duration']
];
}
private function generateReport() {
$report = [
'summary' => $this->generateSummary(),
'detailed_results' => $this->results,
'monitoring_data' => $this->monitoringData,
'performance_analysis' => $this->analyzeOverallPerformance()
];
return $report;
}
private function generateSummary() {
$total = count($this->results);
$successful = 0;
$totalDuration = 0;
$totalData = 0;
foreach ($this->results as $result) {
if ($result['success']) {
$successful++;
$totalDuration += $result['duration'];
$totalData += strlen($result['body']);
}
}
return [
'total_requests' => $total,
'successful_requests' => $successful,
'success_rate' => $total > 0 ? round(($successful / $total) * 100, 1) : 0,
'average_duration' => $successful > 0 ? round($totalDuration / $successful, 3) : 0,
'total_data_transferred' => $totalData,
'total_data_mb' => round($totalData / 1024 / 1024, 2)
];
}
private function analyzeOverallPerformance() {
if (empty($this->results)) {
return ['无数据可用于分析'];
}
$durations = [];
foreach ($this->results as $result) {
if ($result['success']) {
$durations[] = $result['duration'];
}
}
if (empty($durations)) {
return ['无成功请求可用于性能分析'];
}
sort($durations);
return [
'fastest_request' => round(min($durations), 3),
'slowest_request' => round(max($durations), 3),
'median_duration' => round($durations[floor(count($durations) / 2)], 3),
'total_execution_time' => round(microtime(true) - $this->startTime, 2)
];
}
public function close() {
foreach ($this->requests as $request) {
if (is_resource($request['handle'])) {
curl_multi_remove_handle($this->multiHandle, $request['handle']);
curl_close($request['handle']);
}
}
if (is_resource($this->multiHandle)) {
curl_multi_close($this->multiHandle);
}
$this->requests = [];
$this->results = [];
$this->monitoringData = [];
}
public function __destruct() {
$this->close();
}
}
// 使用高级监控器
$monitor = new AdvancedMultiMonitor();
// 添加多个请求进行监控
$urls = [
'fast_api' => 'https://httpbin.org/delay/1',
'medium_api' => 'https://httpbin.org/delay/2',
'slow_api' => 'https://httpbin.org/delay/3',
'json_api' => 'https://httpbin.org/json',
'xml_api' => 'https://httpbin.org/xml'
];
foreach ($urls as $id => $url) {
$monitor->addRequest($url, $id, ['type' => 'api_call']);
}
$report = $monitor->execute();
// 显示报告摘要
$summary = $report['summary'];
echo "\n=== 执行报告摘要 ===\n";
echo "总请求数: {$summary['total_requests']}\n";
echo "成功请求: {$summary['successful_requests']}\n";
echo "成功率: {$summary['success_rate']}%\n";
echo "平均耗时: {$summary['average_duration']} 秒\n";
echo "总数据传输: {$summary['total_data_mb']} MB\n";
// 显示性能分析
$performance = $report['performance_analysis'];
echo "\n=== 性能分析 ===\n";
echo "最快请求: {$performance['fastest_request']} 秒\n";
echo "最慢请求: {$performance['slowest_request']} 秒\n";
echo "中位数耗时: {$performance['median_duration']} 秒\n";
echo "总执行时间: {$performance['total_execution_time']} 秒\n";
$monitor->close();
@endphp
// 执行完成后读取所有信息
while ($info = curl_multi_info_read($mh)) {
$handle = $info['handle'];
if ($info['result'] === CURLE_OK) {
// 处理成功请求
$content = curl_multi_getcontent($handle);
}
// 清理资源
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
}
最简单的使用模式,在所有请求完成后一次性处理。
// 在执行循环中实时处理
do {
curl_multi_exec($mh, $active);
// 实时读取完成信息
while ($info = curl_multi_info_read($mh)) {
// 立即处理完成请求
processCompletedRequest($info);
}
if ($active) {
curl_multi_select($mh, 0.1);
}
} while ($active > 0);
边执行边处理,适合长时间运行或需要即时响应的场景。
// 监控队列深度
$msgsInQueue = null;
while ($info = curl_multi_info_read($mh, $msgsInQueue)) {
processRequest($info);
echo "剩余队列: {$msgsInQueue}\n";
}
使用 msgs_in_queue 参数监控信息队列深度。
while ($info = curl_multi_info_read($mh)) {
if ($info['result'] === CURLE_OK) {
handleSuccess($info);
} else {
handleError($info);
// 可以根据错误代码决定是否重试
if (shouldRetry($info['result'])) {
retryRequest($info['handle']);
}
}
}
根据结果代码进行不同的错误处理策略。
result 字段判断请求成功与否msgs_in_queue 参数了解队列状态| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 遗漏完成请求 | 没有循环读取直到返回 FALSE | 使用 while 循环确保读取所有信息:while ($info = curl_multi_info_read($mh)) |
| 资源泄漏 | 读取信息后没有清理句柄 | 及时调用 curl_multi_remove_handle() 和 curl_close() |
| 请求挂起 | 在 curl_multi_exec() 完成前读取信息 | 确保在 curl_multi_exec() 返回 active=0 后或在其循环中读取 |
| 无法找到对应句柄 | 句柄标识管理不当 | 使用关联数组维护句柄与请求的映射关系 |
msgs_in_queue 参数表示调用后剩余的队列消息数,不是总消息数result 字段判断成功与否