zoukankan      html  css  js  c++  java
  • 使用curl实现多线程

    使用curl实现多线程

    curl一般用来抓取网页,第二种就是get或者post数据,第三种应用就是实现PHP的多线程任务

    下面来实现多线程的

     
    <?php
    /*
    curl 多线程抓取
    */
    
     /**
         * curl 多线程
         *
         * @param array $array 并行网址
         * @param int $timeout 超时时间
         * @return array
         */
     function Curl_http($array,$timeout){
        $res = array();
        $mh = curl_multi_init();//创建多个curl语柄
        $startime = getmicrotime();
        foreach($array as $k=>$url){
            $conn[$k]=curl_init($url);
    
            curl_setopt($conn[$k], CURLOPT_TIMEOUT, $timeout);//设置超时时间
            curl_setopt($conn[$k], CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
            curl_setopt($conn[$k], CURLOPT_MAXREDIRS, 7);//HTTp定向级别
            curl_setopt($conn[$k], CURLOPT_HEADER, 0);//这里不要header,加块效率
            curl_setopt($conn[$k], CURLOPT_FOLLOWLOCATION, 1); // 302 redirect
            curl_setopt($conn[$k],CURLOPT_RETURNTRANSFER,1);
            curl_multi_add_handle ($mh,$conn[$k]);
        }
         //防止死循环耗死cpu 这段是根据网上的写法
            do {
                $mrc = curl_multi_exec($mh,$active);//当无数据,active=true
            } while ($mrc == CURLM_CALL_MULTI_PERFORM);//当正在接受数据时
            while ($active and $mrc == CURLM_OK) {//当无数据时或请求暂停时,active=true
                if (curl_multi_select($mh) != -1) {
                    do {
                        $mrc = curl_multi_exec($mh, $active);
                    } while ($mrc == CURLM_CALL_MULTI_PERFORM);
                }
            }
    
        foreach ($array as $k => $url) {
              curl_error($conn[$k]);
              $res[$k]=curl_multi_getcontent($conn[$k]);//获得返回信息
              $header[$k]=curl_getinfo($conn[$k]);//返回头信息
              curl_close($conn[$k]);//关闭语柄
              curl_multi_remove_handle($mh  , $conn[$k]);   //释放资源
            }
    
            curl_multi_close($mh);
            $endtime = getmicrotime();
            $diff_time = $endtime - $startime;
    
            return array('diff_time'=>$diff_time,
                         'return'=>$res,
                        'header'=>$header
                        );
    
     }
     //计算当前时间
     function getmicrotime() {
            list($usec, $sec) = explode(" ",microtime());
            return ((float)$usec + (float)$sec);
        }
    
        //测试一下,curl 三个网址
        $array = array(
                    "http://www.weibo.com/",
                    "http://www.renren.com/",
                    "http://www.qq.com/"
                    );
    
        $data = Curl_http($array,'10');//调用
        var_dump($data);//输出
    
    ?>
     

    关于do while的那段解释:

    因为$active要等全部url数据接受完毕才变成false,所以这里用到了curl_multi_exec的返回值判断是否还有数据,
    当有数 据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。
     

    这个多线程的写法步骤:

    第一步:调用curl_multi_init 第二步:循环调用curl_multi_add_handle 这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。 第三步:持续调用curl_multi_exec 第四步:根据需要循环调用curl_multi_getcontent获取结果 第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close 第六步:调用curl_multi_close

    多线程的测试效果图:

    wps_clip_image-11562

    总结:36个http请求,从执行的是时间顺序上来看,三个网站的ip交叉,说明是同时并发的!

    下面是更加详细的解析:
    转自:http://xiemingqiang101.blog.163.com/blog/static/586736602008112151559777/   相信许多人对php手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子。
    curl_multi_add_handle

    curl_multi_close

    curl_multi_exec

    curl_multi_getcontent

    curl_multi_info_read

    curl_multi_init

    curl_multi_remove_handle

    curl_multi_select

    一般来说,想到要用这些函数时,目的显然应该是要同时请求多个url,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。

    步骤总结如下:

    第一步:调用curl_multi_init 第二步:循环调用curl_multi_add_handle 这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。 第三步:持续调用curl_multi_exec 第四步:根据需要循环调用curl_multi_getcontent获取结果 第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close 第六步:调用curl_multi_close

    这里有一个网上找的简单例子,其作者称为dirty的例子,(稍后我会说明为何dirty):

    /* Here's a quick and dirty example for curl-multi from PHP, tested on PHP 5.0.0RC1 CLI / FreeBSD 5.2.1 */    $connomains = array( "http://www.cnn.com/", "http://www.canada.com/", "http://www.yahoo.com/" ); $mh = curl_multi_init(); foreach ($connomains as $i => $url) { $conn[$i]=curl_init($url); curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,1); curl_multi_add_handle ($mh,$conn[$i]); } do { $n=curl_multi_exec($mh,$active); } while ($active); foreach ($connomains as $i => $url) { $res[$i]=curl_multi_getcontent($conn[$i]); curl_close($conn[$i]); } print_r($res);  

    整个使用过程差不多就是这样,但是,这个简单代码有个致命弱点,就是在do循环的那段,在整个url请求期间是个死循环,它会轻易导致CPU占用100%。

    现在我们来改进它,这里要用到一个几乎没有任何文档的函数curl_multi_select了,虽然C的curl库对select有说明,但是,php里的接口和用法确与C中有不同。

    把上面do的那段改成下面这样:

                    do { $mrc = curl_multi_exec($mh,$active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active and $mrc == CURLM_OK) { if (curl_multi_select($mh!= -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } }

    因为$active要等全部url数据接受完毕才变成false,所以这里用到了curl_multi_exec的返回值判断是否还有数据,当有数 据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓 消耗没有了。

    另外:还有一些细节的地方可能有时候要遇到:

    控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做: curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);

    判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error($conn[$i]);

  • 相关阅读:
    saltstack远程执行
    centos7防火墙的关闭和禁用
    saltstack 安装使用
    flask基础-第一个flask-jinja2-response三剑客-request-session
    linux服务器排查病毒纪实
    读完这篇文章,就基本搞定了Redis主从复制
    Django学习【第26篇】:中介模型以及优化查询以及CBV模式
    Django学习【第26篇】:后端CORS解决跨域问题
    Django学习【第25篇】:前端Jsonp解决跨域问题
    Django学习【第24篇】:JS实现的ajax和同源策略
  • 原文地址:https://www.cnblogs.com/gxldan/p/4066862.html
Copyright © 2011-2022 走看看