PHP并行编程探索之二(curl_multi函数组)

来源:互联网 发布:windows10数据库 编辑:程序博客网 时间:2024/06/05 21:11

      使用pcntl扩展实现的多进程终究只能运行在命令行模式,而我们接触的基本上都处在http请求模式下,那就真没有解决办法了么,有人说用curl,自身请求自身,好我们用curl看一下是不是有用:

       为方便访问和调试,我使用的是CI框架,直接在控制器里操作。

1. 使用curl

(1) 首先我们添加一个耗时计算函数

function microtime_float()    {        list($usec, $sec) = explode(" ", microtime());        return ((float)$usec + (float)$sec);    }

(2) 然后直接使用Welcome.php 下的Welcome 控制器

class Welcome extends CI_Controller {public function index()    {         $url = 'http://web.iyy.com/welcome/task?task_id=';        $start=microtime_float();        $len = 2;        for($i=0;$i<$len; $i++){            $this->curl($url.$i);        }               $end=microtime_float();        echo "\n",$end-$start;    }        public function curl($url)    {        $ch = curl_init();        curl_setopt($ch, CURLOPT_URL, $url);        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        curl_setopt($ch, CURLOPT_HEADER, 0);        $output = curl_exec($ch);        curl_close($ch);        return $output;    }        public function task()    {        $task_id = $_REQUEST['task_id'];        if($task_id == 0){            sleep(2);  //模拟任务执行时间 2s            echo '2222'."\n";        }else{            sleep(3); //模拟任务执行时间 3s            echo '3333'."\n";        }    }}

这个例子里,我们做了一个循环请求curl,然后使用参数控制请求的任务,使用sleep模拟任务耗时,最终执行结果如下:


根据运行结果,我们看到,curl并没有给我们什么实质性的改变,仍然花费了5s多完成。


2. 使用curl_multi函数组

(1)  引入curl_multi封装类

class MultiCurl{    /*@var array $config*/    private $config = array();    /*@var string $baseUrl*/    private $baseUrl = '';    /**     * @todo: 设置基础路径     */    public function setBaseUrl($url = '')    {        $this->baseUrl = $url;        return $this;    }    /**     * @todo: 设置配置参数     */    public function setConfig($config = array())    {        $baseUrl = $this->baseUrl ? $this->baseUrl : '';        foreach($config as $val){            $this->config[] = array(                'url' => $baseUrl . $val['url']            );        }        return $this;    }    /**     * @todo: 获取查询结果     */    public function getRes()    {        //2.加入子curl         $ch_arr= array();        $mh = curl_multi_init();        foreach($this->config as $k=>$val){        $ch_arr[$k] = curl_init();        curl_setopt($ch_arr[$k], CURLOPT_URL, $val['url']);        if(isset($ch_arr[$k]['configs'])){        foreach($ch_arr[$k]['configs'] as $kconfig => $config){            curl_setopt($ch_arr[$k], $kconfig, $config);        }        }            curl_setopt($ch_arr[$k], CURLOPT_HEADER, 0);        curl_multi_add_handle($mh,$ch_arr[$k]);        }        //3.执行curl        $active = null;        do {            $mrc = curl_multi_exec($mh, $active);        } while ($mrc == CURLM_CALL_MULTI_PERFORM);        while ($active && $mrc == CURLM_OK) {            if (curl_multi_select($mh) == -1) {                usleep(100);            }            do {                $mrc = curl_multi_exec($mh, $active);            } while ($mrc == CURLM_CALL_MULTI_PERFORM);        }        //4.关闭子curl        foreach($ch_arr as $val){            curl_multi_remove_handle($mh, $val);        }        //5.关闭父curl        curl_multi_close($mh);        //6.获取执行结果        foreach($ch_arr as $val){        $response[] = curl_multi_getcontent($val);        }        return $response;    }}


(2) 更改welcome控制器

class Welcome extends CI_Controller {public function index()    {        $start=microtime_float();        $multicurl = new MultiCurl();        $baseurl = 'http://web.iyy.com';        $curl_configs = array(            array('url'=> '/welcome/task?task_id=0'),            array('url'=> '/welcome/task?task_id=1')        );        $res = $multicurl->setBaseUrl($baseurl)->setConfig($curl_configs)->getRes();        $end=microtime_float();        echo "\n",$end-$start;    }        public function task()    {        $task_id = $_REQUEST['task_id'];        if($task_id == 0){            sleep(2);  //模拟任务执行时间 2s            echo '2222'."\n";        }else{            sleep(3); //模拟任务执行时间 3s            echo '3333'."\n";        }    }}

这里我们使用了curl_multi函数组,同样的使用curl请求,我们看返回的结果:


看来两个任务都执行完了,但是基本上,只耗费了最长任务需要的时间,并不是两个任务的总时间,符合我们并行编程的需求,但是话又说回来了,如果我们

并发量很大的前提下,每个请求同时发起两个或者更多的请求,那负载就又上来了,速度是提上来了,访问极限量却变小了,所以这个方案,只能适合访问数不多,但是要考虑访问效率的网站