PHP CURL 异步测试
需求, 请求第三方接口获取数据, 单个接口0.1秒, 如果有10万个接口, 那么岂不是得1万秒才能请求完, 所以使用PHP异步测试一下, 其他的方法还有:
1.使用队列, SupserVior 开多个进程
2.使用Guzzle(异步)
3.使用Swoole协程
4.直接使用多进程等
不过最好的方法应该还是使用异步, 不过可能存在两个缺点
1.异步不是很方便后续的逻辑处理, 应为它是一起请求的
2.并发请求会导致第三方接口可能处理不了, 导致503错误,或者是cpu满载(请求淘宝IP查询的接口出现过)
这里做个测试,使用淘宝的一个商品查询接口做请求
一.不使用异步
<?php /** * 1个请求 耗时 0.19000s, 平均每个耗时:0.19000s * 10个请求 耗时 1.60000s, 平均每个耗时:0.16000s * 100个请求 耗时 14.92400s, 平均每个耗时:0.14924s * 1000个请求 超时 * */ set_time_limit(0); $time = microtime(true); echo '<pre>开始时间' . date('Y-m-d H:i:s', time()) . '<br>'; $data = $res =[]; $count = 1000; for ($i=0; $i <$count ; $i++) { $url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3&callback=cb'; $res[] = curl_request($url); } function curl_request($url, $post='', $cookie='', $returnCookie=0) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($curl, CURLOPT_AUTOREFERER, 1); curl_setopt($curl, CURLOPT_REFERER, "http://XXX"); //关闭SSL验证 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); if($post) { curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post)); } else { //curl_setopt($curl, CURLOPT_POST, 1); //使用后大概快了20%, 但是这个是post请求的 } if($cookie) { curl_setopt($curl, CURLOPT_COOKIE, $cookie); } curl_setopt($curl, CURLOPT_HEADER, $returnCookie); curl_setopt($curl, CURLOPT_TIMEOUT, 10); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $data = curl_exec($curl); if (curl_errno($curl)) { return curl_error($curl); } curl_close($curl); if($returnCookie){ list($header, $body) = explode("\r\n\r\n", $data, 2); preg_match_all("/Set\-Cookie:([^;]*);/", $header, $matches); $info['cookie'] = substr($matches[1][0], 1); $info['content'] = $body; return $info; }else{ return $data; } } $cost = microtime(true) - $time; echo "结束时间" . date('Y-m-d H:i:s', time()) . ', 耗时 '. sprintf('%.5f', $cost) . 's, 平均每个耗时:' . sprintf('%.5f', $cost / $count) . 's <br>'; var_dump($res);
二.使用异步请求
<?php /** * 1个请求 耗时 0.16300s 平均每个耗时:0.16300s * 10个请求 耗时 0.33500s 平均每个耗时:0.03350s * 100个请求 耗时 1.62600s, 平均每个耗时:0.01626s * 1000个请求 耗时 22.27700s, 平均每个耗时:0.02228s * */ $time = microtime(true); echo '<pre>开始时间' . date('Y-m-d H:i:s', time()) . '<br>'; set_time_limit(0); $data = []; $count = 1000; for ($i=0; $i <$count ; $i++) { $url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3&callback=cb'; $data[]['url'] = $url; } function getMultiCurlResult($data = [], $timeout = 120) { $request = []; $requestResource = curl_multi_init(); foreach ($data as $k => $v) { $option = [ CURLOPT_TIMEOUT => $timeout,//请求超时时间,防止死循环 CURLOPT_RETURNTRANSFER => true,//获取的信息以文件流的形式返回,而不是直接输出。 ]; if (!isset($v['url']) || !$v['url']) return null; $option[CURLOPT_URL] = trim($v['url']); if (stripos($v['url'], 'https') === 0) $option[CURLOPT_SSL_VERIFYPEER] = false; if (isset($v['data'])) {//如果设置了请求参数,则是POST请求 $option[CURLOPT_POST] = true; $option[CURLOPT_POSTFIELDS] = http_build_query($v['data']); } //启动一个curl会话 $request[$k] = curl_init(); //设置请求选项 curl_setopt_array($request[$k], $option); //添加请求句柄 curl_multi_add_handle($requestResource, $request[$k]); } $running = null; $result = []; do {//执行批处理句柄 //CURLOPT_RETURNTRANSFER如果为0,这里会直接输出获取到的内容.如果为1,后面可以用curl_multi_getcontent获取内容. curl_multi_exec($requestResource, $running); //阻塞直到cURL批处理连接中有活动连接,不加这个会导致CPU负载超过90%. curl_multi_select($requestResource); } while ($running > 0); foreach ($request as $k => $v) { $result[$k] = curl_multi_getcontent($v); curl_multi_remove_handle($requestResource, $v); } curl_multi_close($requestResource); return $result; } $res = getMultiCurlResult($data); $cost = microtime(true) - $time; echo "结束时间" . date('Y-m-d H:i:s', time()) . ', 耗时 '. sprintf('%.5f', $cost) . 's, 平均每个耗时:' . sprintf('%.5f', $cost / $count) . 's <br>'; var_dump($res);
可以看出,异步的效果还是很明显的