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 相关文章推荐
PHP使用适合阅读的格式显示文件大小的方法
Mar 05 PHP
php保存信息到当前Session的方法
Mar 16 PHP
PHP函数实现从一个文本字符串中提取关键字的方法
Jul 01 PHP
PHP导入导出Excel代码
Jul 07 PHP
thinkphp 手机号和用户名同时登录
Jan 20 PHP
PHP实现活动人选抽奖功能
Apr 19 PHP
PHP实现的登录页面信息提示功能示例
Jul 24 PHP
Yii2.0实现生成二维码功能实例
Oct 24 PHP
php大小写转换函数(strtolower、strtoupper)用法介绍
Nov 17 PHP
自写的利用PDO对mysql数据库增删改查操作类
Feb 19 PHP
详解php中curl返回false的解决办法
Mar 18 PHP
php常用的工具开发整理
Sep 26 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
Apache下禁止php文件被直接访问的解决方案
2013/04/25 PHP
PHP设计模式之迭代器模式的深入解析
2013/06/13 PHP
PHP数组操作简单案例分析
2016/10/15 PHP
Thinkphp实现短信验证注册功能
2016/10/18 PHP
JavaScript 面向对象与原型
2015/04/10 Javascript
JavaScript中的anchor()方法使用详解
2015/06/08 Javascript
介绍一个简单的JavaScript类框架
2015/06/24 Javascript
jQuery+jsp实现省市县三级联动效果(附源码)
2015/12/03 Javascript
JavaScript引用类型和基本类型详解
2016/01/06 Javascript
domReady的实现案例
2016/11/23 Javascript
canvas绘制的直线动画
2017/01/23 Javascript
Angular5中提取公共组件之radio list的实例代码
2018/07/10 Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
2020/05/06 Javascript
vue 解决uglifyjs-webpack-plugin打包出现报错的问题
2020/08/04 Javascript
js实现贪吃蛇游戏 canvas绘制地图
2020/09/09 Javascript
[59:00]DOTA2-DPC中国联赛 正赛 Ehome vs PSG.LGD BO3 第一场 3月7日
2021/03/11 DOTA
python实现的守护进程(Daemon)用法实例
2015/06/02 Python
遍历python字典几种方法总结(推荐)
2016/09/11 Python
Python中的上下文管理器和with语句的使用
2018/04/17 Python
python语音识别实践之百度语音API
2018/08/30 Python
Python实现的读取文件内容并写入其他文件操作示例
2019/04/09 Python
Python DataFrame一列拆成多列以及一行拆成多行
2019/08/06 Python
Python 多线程,threading模块,创建子线程的两种方式示例
2019/09/29 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
python下载卫星云图合成gif的方法示例
2020/02/18 Python
Pytest单元测试框架如何实现参数化
2020/09/05 Python
关于Python 解决Python3.9 pandas.read_excel(‘xxx.xlsx‘)报错的问题
2020/11/28 Python
世界上最好的帽子:Tilley
2016/11/27 全球购物
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
自我鉴定书面格式
2014/01/13 职场文书
大学四年的个人自我评价
2014/01/14 职场文书
少先队入队活动方案
2014/02/08 职场文书
《湘夫人》教学反思
2014/02/21 职场文书
教师专业自荐信
2014/05/31 职场文书
地陪导游欢迎词
2015/01/26 职场文书
Python 类,对象,数据分类,函数参数传递详解
2021/09/25 Python