php 非阻塞post请求,PHP的非阻塞或并行请求实现方式

我们都知道,php是串行请求的,我们在碰到以下几个场景的时候,php的效率会变的比较低下:

1:一个请求,在输出结果前,有比较长时间的耗时操作(但这个操作不影响输出结果),这时候,客户端会等待比较长的时间。

2:如果我要同时获得多个远程接口的结果,耗时是所有接口响应耗时之和

那么,有没有办法来提升上述场景的效率呢?

答案是肯定的:

1:针对第一个场景,若你使用的是FastCGI模式 ,使用fastcgi_finish_request()能把结果输出到客户端,但PHP进程继续在跑

fastcgi_finish_request();echo"xtgxiso"//这儿结束之后的执行

备注:此方式不能算是非阻塞,只是把结果尽快输出到客户端,但本身这个php进程还是被阻塞的占用着。

2:使用curl_multi_init的方法,进行并行url请求

$time=time();// 创建3个cURL资源$ch1=curl_init();$ch2=curl_init();$ch3=curl_init();// 设置URL和相应的选项curl_setopt($ch1,CURLOPT_URL,

"http://test.xtgxiso.cn/sleep1.php");curl_setopt($ch1,CURLOPT_HEADER, 0);curl_setopt($ch2,CURLOPT_URL,

"http://test.xtgxiso.cn/sleep2.php");curl_setopt($ch2,CURLOPT_HEADER, 0);curl_setopt($ch3,CURLOPT_URL,

"http://test.xtgxiso.cn/sleep3.php");curl_setopt($ch3,CURLOPT_HEADER, 0);// 创建批处理cURL句柄$mh=curl_multi_init();// 增加3个句柄curl_multi_add_handle($mh,$ch1);curl_multi_add_handle($mh,$ch2);curl_multi_add_handle($mh,$ch3);$running=null;// 执行批处理句柄do {usleep(10000);curl_multi_exec($mh,$running);}

while ($running> 0);// 关闭全部句柄curl_multi_remove_handle($mh,$ch1);curl_multi_remove_handle($mh,$ch2);curl_multi_remove_handle($mh,$ch3);curl_multi_close($mh);echo"\n total time : ".(time()-$time)."\n";

3:使用stream_set_blocking + select方法,进行并行url请求

// url数组,每个url发送一个请求$urls=array("sleep1.php","sleep2.php","sleep3.php");// 保存socket的数组$sockets=array();$time=time();// 批量创建链接并发送数据foreach($urlsas$url){$socket=stream_socket_client("tcp://test.xtgxiso.cn:80",$errno,$errstr, 3);// 设置成非阻塞stream_set_blocking($socket, 0);fwrite($socket, "GET /{$url} HTTP/1.0\r\nHost: test.xtgxiso.cn\r\nAccept: */*\r\n\r\n");// 记录数组$sockets[(int)$socket] =$socket;}// 批量等待数据返回while(count($sockets)>0){$read=$sockets;$write=$e=array();// 等待数据可读if(stream_select($read,$write,$e, 10)){// 循环读数据foreach($readas$socket){// 这里是服务端返回的数据,需要的话可以循环读echo fread($socket, 8192)."\n";// 数据读取完毕关闭链接,并删除链接fclose($socket);unset($sockets[(int)$socket]);}}}echo time()-$time;echo"\n";

上面两种方式请求多个url的时候,时间由原来的所有请求响应时间之和变为只是最长的那个请求的响应时间(如请求1:10ms,请求2:15ms,请求3:20ms,串行处理的时间将是:45ms,而并行处理的时间只有:25ms),从而提高效率和并发,我们可以封装个get请求的方法,post方法和get类似!

functionhttp_get_url($arr=''){if (is_array($arr) &&$arr){$sockets=array();foreach($arras$url){$url_info=parse_url($url);if ( !@$url_info["port"] ){$url_info["port"] = 80;}$socket=stream_socket_client("tcp://".$url_info["host"].":".$url_info["port"],$errno,$errstr,3);if ($socket) {stream_set_blocking($socket, 0);$str= "GET ".$url_info["path"]."?".$url_info["query"]." HTTP/1.0\r\nHost: ".$url_info["host"]."\r\nAccept: */*\r\n\r\n";echo $str;fwrite($socket,$str);$sockets[(int)$socket] =$socket;}}while(count($sockets)>0){$read=$sockets;$write=$e=array();if(stream_select($read,$write,$e, 3)){foreach($readas$socket){$result[(int)$socket] .=fread($socket, 8192);unset($sockets[(int)$socket]);}}}foreach ($resultas$k=>$v) {$result[$k] =trim(strstr($v,"\r\n\r\n"),"\r\n");}return$result;}else if ($arr){$curl=curl_init();curl_setopt($curl,CURLOPT_URL,$arr);curl_setopt($curl,CURLOPT_HEADER, 0);curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);curl_setopt($curl,CURLOPT_TIMEOUT_MS,3000);curl_setopt($curl,CURLOPT_FOLLOWLOCATION, 1);curl_setopt($curl,CURLOPT_MAXREDIRS, 3);$result=curl_exec($curl);curl_close($curl);return$result;}else{return false;}}

这个方法可以get一个或多个url,尤其在多个的时候,可以提高效率!

备注:

1: curl_multi和stream_select 都是调用 系统的select进行多路i/o复用

2: 并行请求的场景,用swoole也更合适,fpm里,通过swoole_client,把url发送到swoole的server, swoole_server天然支持并行请求,把汇总的结果返回到fpm。

3:开启PHP子进程也是一个并行的方法,不过回收有些麻烦。

下次说说多路i/o复用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值