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 相关文章推荐
第十四节 命名空间 [14]
Oct 09 PHP
php dirname(__FILE__) 获取当前文件的绝对路径
Jun 28 PHP
给初学者的30条PHP最佳实践(荒野无灯)
Aug 02 PHP
php中长文章分页显示实现代码
Sep 29 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十三)
Jun 26 PHP
PHP封装分页函数实现文本分页和数字分页
Oct 23 PHP
php采用session实现防止页面重复刷新
Dec 24 PHP
PHP使用pear实现mail发送功能 windows环境下配置pear
Apr 15 PHP
PHP XML和数组互相转换详解
Oct 26 PHP
利用PHP扩展Xhprof分析项目性能实践教程
Sep 05 PHP
使用PHPUnit进行单元测试并生成代码覆盖率报告的方法
Mar 08 PHP
laravel框架select2多选插件初始化默认选中项操作示例
Feb 18 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
解决MySQL中文输出变成问号的问题
2008/06/05 PHP
qq登录,新浪微博登录接口申请过程中遇到的问题
2014/07/22 PHP
php闭包中使用use声明变量的作用域实例分析
2018/08/09 PHP
PHP从尾到头打印链表实例讲解
2018/09/27 PHP
phpinfo无法显示的原因及解决办法
2019/02/15 PHP
详解PHP多个进程配合redis的有序集合实现大文件去重
2019/03/06 PHP
js window.print实现打印特定控件或内容
2013/09/16 Javascript
js使用removeChild方法动态删除div元素
2014/08/01 Javascript
javascript实现图片循环渐显播放的方法
2015/02/24 Javascript
JavaScript获取按钮所在form表单id的方法
2015/04/02 Javascript
jQuery封装的屏幕居中提示信息代码
2016/06/08 Javascript
vue的props实现子组件随父组件一起变化
2016/10/27 Javascript
关于Vue Webpack2单元测试示例详解
2017/08/14 Javascript
自己动手封装一个React Native多级联动
2018/09/19 Javascript
解决vue.js提交数组时出现数组下标的问题
2019/11/05 Javascript
解决vue-cli 打包后自定义动画未执行的问题
2019/11/12 Javascript
d3.js 地铁轨道交通项目实战
2019/11/27 Javascript
微信小程序地图绘制线段并且测量(实例代码)
2020/01/02 Javascript
javascript实现页面的实时时钟显示示例
2020/08/06 Javascript
vue3.0生命周期的示例代码
2020/09/24 Javascript
[01:03:56]Mineski vs TNC 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
python文件和目录操作函数小结
2014/07/11 Python
Python使用matplotlib的pie函数绘制饼状图功能示例
2018/01/08 Python
Python3多进程 multiprocessing 模块实例详解
2018/06/11 Python
python用pandas数据加载、存储与文件格式的实例
2018/12/07 Python
浅谈pyqt5中信号与槽的认识
2019/02/17 Python
Django如何继承AbstractUser扩展字段
2020/11/27 Python
美国领先的商务贺卡出版商:The Gallery Collection
2018/02/13 全球购物
Pretty Green美国:英式摇滚服饰风格代表品牌之一
2019/01/23 全球购物
澳大利亚在线批发商:Simply Wholesale
2021/02/24 全球购物
新锐科技Java程序员面试题
2016/07/25 面试题
基层党支部整改方案
2014/10/25 职场文书
爱心募捐感谢信
2015/01/22 职场文书
大专护理专业自荐信
2015/03/25 职场文书
Python帮你解决手机qq微信内存占用太多问题
2022/02/15 Python
spring IOC容器的Bean管理XML自动装配过程
2022/05/30 Java/Android