PHP实现非阻塞模式的方法分析


Posted in PHP onJuly 26, 2018

本文实例讲述了PHP实现非阻塞模式的方法。分享给大家供大家参考,具体如下:

程序非阻塞模式,这里也可以理解成并发。而并发又暂且可以分为网络请求并发本地并发

先说一下网络请求并发

理论描述

假设有一个client,程序逻辑是要请求三个不同的server,处理各自的响应。传统模型当然是顺序执行,先发送第一个请求,等待收到响应数据后再发送第二个请求,以此类推。就像是单核CPU,一次只能处理一件事,其他事情被暂时阻塞。而并发模式可以让三个server同时处理各自请求,这就可以使大量时间复用。

画个图更好说明问题:

PHP实现非阻塞模式的方法分析

前者为阻塞模式,忽略请求响应等时间,总耗时为700ms;而后者非阻塞模式,由于三个请求可以同时得到处理,总耗时只有300ms。

代码实现

<?php
echo "Program starts at ". date('h:i:s') . "./n";
$timeout = 3;
$sockets = array(); //socket句柄数组
//一次发起多个请求
$delay = 0;
while ($delay++ < 3)
{
  $sh = stream_socket_client("localhost:80", $errno, $errstr, $timeout,
      STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
  /* 这里需要稍微延迟一下,否则下面fwrite中的socket句柄不一定能真正使用
    这里应该是PHP的一处bug,查了一下,官方bug早在08年就有人提交了
    我的5.2.8中尚未解决,不知最新的5.3中是否修正
  */
  usleep(10);
  if ($sh) {
    $sockets[] = $sh;
    $http_header = "GET /test.php?n={$delay} HTTP/1.0/r/n";
    $http_header .= "Host: localhost/r/n";
    $http_header .= "Accept: */*/r/n";
    $http_header .= "Accept-Charset: */r/n";
    $http_header .= "/r/n";
    fwrite($sh, $http_header);
  } else {
    echo "Stream failed to open correctly./n";
  }
}
//非阻塞模式来接收响应
$result = array();
$read_block_size = 8192;
while (count($sockets))
{
  $read = $sockets;
  $n = stream_select($read, $w=null, $e=null, $timeout);
  //if ($n > 0) //据说stream_select返回值不总是可信任的
  if (count($read))
  {
    /* stream_select generally shuffles $read, so we need to
      compute from which socket(s) we're reading. */
    foreach ($read as $r)
    {
      $id = array_search($r, $sockets);
      $data = fread($r, $read_block_size);
      if (strlen($data) == 0)
      {
        echo "Stream {$id} closes at " . date('h:i:s') . "./n";
        fclose($r);
        unset($sockets[$id]);
      } else {
        if (!isset($result[$id])) $result[$id] = '';
        $result[$id] .= $data;
      }
    }
  } else {
    echo "Time-out!/n";
    break;
  }
}
//print_r($result);

几点说明:

1、使用stream_socket_client函数链接请求服务器和端口(简便起见这里使用同一地址localhost)。这里不受限于http协议,可广泛用于所有TCP/IP协议。详细内容请参考手册。

2、这里链接成功后通过发送各自http头信息来获取不同响应(这里使用网站根目录下的test.php做服务端)。

3、发送header前需要个微小的延迟,代码中已经做了注释。

CLI模式运行结果:

PHP实现非阻塞模式的方法分析

多运行几次会发现,三次请求结束顺序是无序的。该demo太过简单导致整个过程一秒内已完成,但可以针对三次不同请求做相应延迟,来看出非阻塞时时间复用的效果。

下面再大概说下本地并发

本地并发只能通过语言自己的特性在程序本身实现多任务效果,一般来说现在的语言会通过多线程或多进程的方式来实现。由于PHP不支持多线程,目前只能采用多进程方式,让操作系统来帮助实现本地并发。

至于代码实现,可以通过pcntl扩展(封装fork等进程控制函数,和C语言中使用非常相似,windows下不可用)、 proc_openpopen等方式,方法不止一种,这里就不做详细介绍了。详情可自行搜索“php多进程”进行了解:)

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
对Session和Cookie的区分与解释
Mar 16 PHP
PHP的substr_replace将指定两位置之间的字符替换为*号
May 04 PHP
php file_put_contents()功能函数(集成了fopen、fwrite、fclose)
May 24 PHP
thinkphp模板输出技巧汇总
Nov 24 PHP
PHP判断来访是搜索引擎蜘蛛还是普通用户的代码小结
Sep 14 PHP
浅谈php+phpStorm+xdebug配置方法
Sep 17 PHP
php加密之discuz内容经典加密方式实例详解
Feb 04 PHP
php脚本守护进程原理与实现方法详解
Jul 20 PHP
PHP实现权限管理功能示例
Sep 22 PHP
ThinkPHP5.0框架控制器继承基类和自定义类示例
May 25 PHP
php5对象复制、clone、浅复制与深复制实例详解
Aug 14 PHP
Laravel开启跨域请求的方法
Oct 13 PHP
php实现等比例压缩图片
Jul 26 #PHP
PHP输出Excel PHPExcel的方法
Jul 26 #PHP
PHP微信H5支付开发实例
Jul 25 #PHP
php app支付宝回调(异步通知)详解
Jul 25 #PHP
php支付宝APP支付功能
Jul 29 #PHP
PHP多个图片压缩成ZIP的方法
Aug 18 #PHP
PHP上传文件及图片到七牛的方法
Jul 25 #PHP
You might like
php str_pad 函数用法简介
2009/07/11 PHP
php以fastCGI的方式运行时文件系统权限问题及解决方法
2015/05/11 PHP
解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题
2020/08/24 PHP
javascript面向对象入门基础详细介绍
2012/09/05 Javascript
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
2013/06/09 Javascript
js使用栈来实现10进制转8进制与取除数及余数
2014/06/11 Javascript
NodeJS学习笔记之MongoDB模块
2015/01/13 NodeJs
javaScript生成支持中文带logo的二维码(jquery.qrcode.js)
2017/01/03 Javascript
AngularJS实现tab选项卡的方法详解
2017/07/05 Javascript
详解angular笔记路由之angular-router
2017/09/12 Javascript
JavaScript canvas实现围绕旋转动画
2017/11/18 Javascript
jQuery实现左右滑动的toggle方法
2018/03/03 jQuery
vue项目中,main.js,App.vue,index.html的调用方法
2018/09/20 Javascript
详解vue 数组和对象渲染问题
2018/09/21 Javascript
VUE 配置vue-devtools调试工具及安装方法
2018/09/30 Javascript
如何实现一个webpack模块解析器
2018/10/24 Javascript
Node.js 如何利用异步提升任务处理速度
2019/01/07 Javascript
layui富文本编辑器前端无法取值的解决方法
2019/09/18 Javascript
JavaScript十大取整方法实例教程
2020/12/03 Javascript
Python判断值是否在list或set中的性能对比分析
2016/04/16 Python
python正则表达式re之compile函数解析
2017/10/25 Python
python计算两个地址之间的距离方法
2018/06/09 Python
Python获取网段内ping通IP的方法
2019/01/31 Python
python进阶之自定义可迭代的类
2019/08/20 Python
六种酷炫Python运行进度条效果的实现代码
2020/07/17 Python
Python文件名匹配与文件复制的实现
2020/12/11 Python
常用的四种CSS透明属性介绍
2014/04/12 HTML / CSS
HTML5的结构和语义(4):语义性的内联元素
2008/10/17 HTML / CSS
boostrap modal 闪现问题的解决方法
2020/09/01 HTML / CSS
最新的咖啡店创业计划书
2013/12/30 职场文书
大学毕业感言
2014/01/10 职场文书
商超业务员岗位职责
2014/03/12 职场文书
低碳环保标语
2014/06/12 职场文书
2014小学生国庆65周年演讲稿
2014/09/21 职场文书
应急管理工作总结2015
2015/05/04 职场文书
用电申请报告范文
2015/05/18 职场文书