好久没写文章啦,比较忙,也没学习新的东西,前不久域名出了问题,从新备案后前几天恢复了。
今天讲一下php中如何提高并发请求一批接口,get请求示例。
常规的curl请求一批接口:
// 循环多次请求接口
$start_time = microtime(true);
$res = [];
$url = 'http://localhost:8080/test/cache';
for ($i = 0; $i < 10; $i++) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res[$i] = curl_exec($ch);
}
//var_dump($res);
echo 'time=' . (microtime(true) - $start_time) . PHP_EOL;
通过foreach循环请求每个接口,这样的话如果每个接口请求需要1秒,那么10个就需要10秒,耗时长,效率很低。
如何提高这个请求一批接口的性能呢?接下来就用到了multi_curl了。
简单介绍一下要用到的方法:
/** 函数作用:返回一个新cURL批处理句柄
@return resource 成功返回cURL批处理句柄,失败返回false
*/
resource curl_multi_init ( void )
/** 函数作用:向curl批处理会话中添加单独的curl句柄
@param $mh 由curl_multi_init返回的批处理句柄
@param $ch 由curl_init返回的cURL句柄
@return resource 成功返回cURL批处理句柄,失败返回false
*/
int curl_multi_add_handle ( resource $mh , resource $ch )
/** 函数作用:运行当前 cURL 句柄的子连接
@param $mh 由curl_multi_init返回的批处理句柄
@param $still_running 一个用来判断操作是否仍在执行的标识的引用
@return 一个定义于 cURL 预定义常量中的 cURL 代码
*/
int curl_multi_exec ( resource $mh , int &$still_running )
/** 函数作用:等待所有cURL批处理中的活动连接
@param $mh 由curl_multi_init返回的批处理句柄
@param $timeout 以秒为单位,等待响应的时间
@return 成功时返回描述符集合中描述符的数量。失败时,select失败时返回-1,否则返回超时(从底层的select系统调用).
*/
int curl_multi_select ( resource $mh [, float $timeout = 1.0 ] )
/** 函数作用:移除cURL批处理句柄资源中的某个句柄资源
说明:从给定的批处理句柄mh中移除ch句柄。当ch句柄被移除以后,仍然可以合法地用curl_exec()执行这个句柄。如果要移除的句柄正在被使用,则这个句柄涉及的所有传输任务会被中止。
@param $mh 由curl_multi_init返回的批处理句柄
@param $ch 由curl_init返回的cURL句柄
@return 成功时返回0,失败时返回CURLM_XXX中的一个
*/
int curl_multi_remove_handle ( resource $mh , resource $ch )
/** 函数作用:关闭一组cURL句柄
@param $mh 由curl_multi_init返回的批处理句柄
@return void
*/
void curl_multi_close ( resource $mh )
/** 函数作用:如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流
@param $ch 由curl_init返回的cURL句柄
@return string 如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流。
*/
string curl_multi_getcontent ( resource $ch )
简单使用:
$start_time = microtime(true);
$ch_arr = [];//保存单个的curl_init资源
$mh = curl_multi_init();
for ($i = 0; $i < 10; $i++) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$ch_arr[$i] = $ch;
curl_multi_add_handle($mh, $ch);//添加
}
$runing = 1;
do {
curl_multi_exec($mh, $runing);
//系统会不停地执行curl_multi_exec()函数。这样可能会轻易导致CPU占用很高
} while ($runing > 0);
$res = [];
foreach ($ch_arr as $ch) {
$res[] = curl_multi_getcontent($ch);//获取请求结果
curl_multi_remove_handle($mh, $ch);//移除
}
curl_multi_close($mh);
//var_dump($res);
echo 'time=' . (microtime(true) - $start_time) . PHP_EOL;
解决一下cpu占用高的问题:
// 并发优化CPU占用高
$start_time = microtime(true);
$ch_arr = [];
$mh = curl_multi_init();
for ($i = 0; $i < 10; $i++) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$ch_arr[$i] = $ch;
curl_multi_add_handle($mh, $ch);
}
$runing = 1;
do {
$mc = curl_multi_exec($mh, $runing);
//当返回值等于CURLM_CALL_MULTI_PERFORM时,表明数据还在写入或读取中,执行循环,
//当第一次$ch句柄的数据写入或读取成功后,返回值变为CURLM_OK,跳出本次循环,进入下面的大循环之中
} while ($mc == CURLM_CALL_MULTI_PERFORM);
while ($runing && $mc == CURLM_OK) {
//阻塞直到cURL批处理连接中有活动连接。成功时返回描述符集合中描述符的数量。失败时,select失败时返回-1
if (curl_multi_select($mh) != -1) {
//$mh批处理中还有可执行的$ch句柄,curl_multi_select($mh) != -1程序退出阻塞状态。
do {
//有活动连接时执行,避免了每次都执行exec
$mc = curl_multi_exec($mh, $runing);
} while ($mc == CURLM_CALL_MULTI_PERFORM);
}
}
$res = [];
foreach ($ch_arr as $ch) {
$res[] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
}
curl_multi_close($mh);
//var_dump($res);
echo 'time=' . (microtime(true) - $start_time) . PHP_EOL;
还存在优化的空间, 当某个URL请求完毕之后尽可能快的去处理它, 边处理边等待其他的URL返回, 而不是等待那个最慢的接口返回之后才开始处理等工作, 从而避免CPU的空闲和浪费。
$res = [];
$start_time = microtime(true);
$mh = curl_multi_init();
for ($i = 0; $i < 10; $i++) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
}
$runing = 1;
do {
$mc = curl_multi_exec($mh, $runing);
//当返回值等于CURLM_CALL_MULTI_PERFORM时,表明数据还在写入或读取中,执行循环,
//当第一次$ch句柄的数据写入或读取成功后,返回值变为CURLM_OK,跳出本次循环,进入下面的大循环之中
} while ($mc == CURLM_CALL_MULTI_PERFORM);
while ($runing && $mc == CURLM_OK) {
//阻塞直到cURL批处理连接中有活动连接。成功时返回描述符集合中描述符的数量。失败时,select失败时返回-1
if (curl_multi_select($mh) != -1) {
//$mh批处理中还有可执行的$ch句柄,curl_multi_select($mh) != -1程序退出阻塞状态。
do {
//有活动连接时执行
$mc = curl_multi_exec($mh, $runing);
// echo 'curl_multi_exec' . PHP_EOL;
} while ($mc == CURLM_CALL_MULTI_PERFORM);
}
while ($done = curl_multi_info_read($mh)) {
// $info = curl_getinfo($done['handle']);
// $error = curl_error($done['handle']);
$results = curl_multi_getcontent($done['handle']);
// echo 'curl_multi_getcontent' . PHP_EOL;
$res[] = $results;
curl_multi_remove_handle($mh, $done['handle']);
curl_close($done['handle']);
}
}
curl_multi_close($mh);
//var_dump($res);
echo 'time=' . (microtime(true) - $start_time) . PHP_EOL;
这样性能就更好了。
最后执行时间依次是:
评论
2