PHP异步HTTP请求与并发调用

PHP异步HTTP请求与并发调用 PHP异步HTTP请求与并发调用同时发送多个HTTP请求可以大幅提升数据采集效率。PHP的curl_multi可以并行发送请求。今天说说PHP中并发HTTP请求的实现。curl_multi批量请求。phpfunction batchHttpGet(array $urls): array{$multi curl_multi_init();$handles [];foreach ($urls as $id $url) {$ch curl_init($url);curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER true, CURLOPT_TIMEOUT 10]);curl_multi_add_handle($multi, $ch);$handles[$id] $ch;}$running null;do {curl_multi_exec($multi, $running);curl_multi_select($multi);} while ($running 0);$results [];foreach ($handles as $id $ch) {$results[$id] [body curl_multi_getcontent($ch), http_code curl_getinfo($ch, CURLINFO_HTTP_CODE)];curl_multi_remove_handle($multi, $ch);curl_close($ch);}curl_multi_close($multi);return $results;}$urls [users https://jsonplaceholder.typicode.com/users,posts https://jsonplaceholder.typicode.com/posts,comments https://jsonplaceholder.typicode.com/comments,];$start microtime(true);$results batchHttpGet($urls);$elapsed (microtime(true) - $start) * 1000;foreach ($results as $name $result) {$data json_decode($result[body], true);echo $name: . count($data) . 条, HTTP {$result[http_code]}\n;}echo 总耗时: . round($elapsed, 2) . ms\n;?Promise风格的异步HTTP客户端。phpclass AsyncHttpClient{private array $pending [];private array $handles [];public function get(string $url, callable $onSuccess null, callable $onError null): string{$id uniqid(req_);$ch curl_init($url);curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER true, CURLOPT_TIMEOUT 10]);$this-pending[$id] [onSuccess $onSuccess, onError $onError];$this-handles[$id] $ch;return $id;}public function wait(): void{if (empty($this-handles)) return;$multi curl_multi_init();foreach ($this-handles as $ch) curl_multi_add_handle($multi, $ch);$running null;do { curl_multi_exec($multi, $running); curl_multi_select($multi); } while ($running 0);foreach ($this-handles as $id $ch) {$body curl_multi_getcontent($ch);$httpCode curl_getinfo($ch, CURLINFO_HTTP_CODE);$error curl_error($ch);$callback $this-pending[$id] ?? [];if ($error $callback[onError]) {($callback[onError])($error);} elseif ($callback[onSuccess]) {($callback[onSuccess])($body, $httpCode);}curl_multi_remove_handle($multi, $ch);curl_close($ch);}curl_multi_close($multi);$this-handles [];$this-pending [];}}$client new AsyncHttpClient();$client-get(https://jsonplaceholder.typicode.com/users, function ($body, $code) {echo 用户API: $code, . strlen($body) . 字节\n;});$client-get(https://jsonplaceholder.typicode.com/posts, function ($body, $code) {echo 文章API: $code, . strlen($body) . 字节\n;});echo 开始等待...\n;$client-wait();echo 所有请求完成\n;?超时控制。phpfunction batchRequestWithTimeout(array $urls, int $timeout 5): array{$multi curl_multi_init();$handles [];foreach ($urls as $id $url) {$ch curl_init($url);curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER true,CURLOPT_TIMEOUT $timeout,CURLOPT_CONNECTTIMEOUT $timeout,]);curl_multi_add_handle($multi, $ch);$handles[$id] $ch;}$running null;$start microtime(true);do {curl_multi_exec($multi, $running);if (microtime(true) - $start $timeout 1) break;curl_multi_select($multi, 1);} while ($running 0);$results [];foreach ($handles as $id $ch) {$body curl_multi_getcontent($ch);$results[$id] [body $body ! false ? $body : null,http_code curl_getinfo($ch, CURLINFO_HTTP_CODE),];curl_multi_remove_handle($multi, $ch);curl_close($ch);}curl_multi_close($multi);return $results;}?并发HTTP请求可以大幅减少数据采集的总时间。curl_multi是PHP中实现并发请求的标准方式。设置超时防止请求挂起处理错误避免单个失败影响全部。