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);

可以看出,异步的效果还是很明显的

posted @ 2019-09-23 20:32  Skrillex  阅读(2316)  评论(0编辑  收藏  举报

power by Skrillex 2008