使用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请求,我们看返回的结果:
看来两个任务都执行完了,但是基本上,只耗费了最长任务需要的时间,并不是两个任务的总时间,符合我们并行编程的需求,但是话又说回来了,如果我们
并发量很大的前提下,每个请求同时发起两个或者更多的请求,那负载就又上来了,速度是提上来了,访问极限量却变小了,所以这个方案,只能适合,访问数不多,但是要考虑访问效率的网站。