使用PHP的curl函数调用多个外部HTTP接口时,默认情况下是需要一个一个执行的,第一个请求结束后才会发起第二个请求,这样会显得效率低。如果各个请求之间没有强依赖关系,可以使用curl的multi系列函数来同时发起多个请求,这样可以节省很多时间,提高效率。
有很多资料说curl_multi是使用多线程来实现并发的,但事实上并不是,它仍然是单线程,只是用了系统的select I/O多路复用机制来实现并发。
<?php
function main() {
$requests = [
[
'url' => 'https://www.baidu.com', // 请求URL
'method' => 'GET', // 请求方法,支持GET和POST
'header' => [], // 请求头
'param' => ['i' => 0], // 请求参数
],
[
'url' => 'http://www.sdhaidhoasdhaihd.com',
'method' => 'GET',
'header' => [],
'param' => ['i' => 1],
],
];
$handles = [];
foreach ($requests as $req) {
$options = [
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
];
if (!empty($req['header'])) {
$options[CURLOPT_HTTPHEADER] = $req['header'];
}
switch ($req['method']) {
case 'GET':
$options[CURLOPT_URL] = "{$req['url']}?" . http_build_query($req['param']);
break;
case 'POST':
$options[CURLOPT_URL] = $req['url'];
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = http_build_query($req['param']);
break;
default:
exit("Unsupported method:{$req['method']}");
}
$ch = curl_init();
curl_setopt_array($ch, $options);
$handles[] = $ch;
}
$mh = curl_multi_init();
foreach ($handles as $ch) {
curl_multi_add_handle($mh, $ch);
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
while ($info = curl_multi_info_read($mh)) {
$ch = $info['handle'];
if ($info['result'] != CURLM_OK) {
$httpCode = $info['result'];
$httpBody = curl_error($ch);
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$httpBody = curl_multi_getcontent($ch);
}
$index = array_search($ch, $handles, true);
$requests[$index]['response'] = [
'code' => $httpCode,
'body' => $httpBody,
];
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
} while ($running > 0);
curl_multi_close($mh);
var_dump($requests);
}
main();