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 27 PHP
php 验证码实例代码
Jun 01 PHP
关于PHP自动判断字符集并转码的详解
Jun 26 PHP
php针对cookie操作的队列操作类实例
Dec 10 PHP
非常实用的PHP常用函数汇总
Dec 17 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
Jan 05 PHP
php上传图片获取路径及给表单字段赋值的方法
Jan 23 PHP
postfixadmin忘记密码后的修改密码方法详解
Jul 20 PHP
PHP中类型转换 ,常量,系统常量,魔术常量的详解
Oct 26 PHP
php如何计算两坐标点之间的距离
Dec 29 PHP
PHP观察者模式实例分析【对比JS观察者模式】
May 22 PHP
php扩展开发入门demo示例
Sep 23 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 图片文件上传实现代码
2010/12/29 PHP
PHP中通过HTTP_USER_AGENT判断是否为手机移动终端的函数代码
2013/02/14 PHP
Yii框架表单提交验证功能分析
2017/01/07 PHP
PHP简单实现遍历目录下特定文件的方法小结
2017/05/22 PHP
不到30行JS代码实现Excel表格的方法
2014/11/15 Javascript
cookie的secure属性详解
2015/04/08 Javascript
js实现带圆角的多级下拉菜单效果
2015/08/28 Javascript
关于javascript中dataset的问题小结
2015/11/16 Javascript
js实现简单的验证码
2015/12/25 Javascript
checkbox 选中一个另一个checkbox也会选中的实现代码
2016/07/09 Javascript
详解微信小程序开发之——wx.showToast(OBJECT)的使用
2017/01/18 Javascript
phantomjs导出html到pdf的方法总结
2017/10/19 Javascript
Vue-cli-webpack搭建斗鱼直播步骤详解
2017/11/17 Javascript
微信小程序用户授权,以及判断登录是否过期的方法
2019/05/10 Javascript
Python中的is和==比较两个对象的两种方法
2017/09/06 Python
Python编程之Re模块下的函数介绍
2017/10/28 Python
python中format()函数的简单使用教程
2018/03/14 Python
python实现旋转和水平翻转的方法
2018/10/25 Python
对python opencv 添加文字 cv2.putText 的各参数介绍
2018/12/05 Python
css3实现椭圆轨迹旋转的示例代码
2018/10/29 HTML / CSS
大学生咖啡店创业计划书
2014/01/21 职场文书
自荐信如何制作?
2014/02/21 职场文书
医学生就业推荐表自我鉴定
2014/03/26 职场文书
高一学生期末评语
2014/04/25 职场文书
环境卫生标语
2014/06/09 职场文书
国际语言毕业生求职信
2014/07/08 职场文书
大学生党员批评与自我批评范文
2014/10/14 职场文书
2014年幼儿园工作总结
2014/11/10 职场文书
房产遗嘱范本
2015/08/06 职场文书
2015年十月一日放假通知
2015/08/18 职场文书
2016党校学习心得体会
2016/01/07 职场文书
2016个人廉洁自律承诺书
2016/03/25 职场文书
在Windows下安装配置CPU版的PyTorch的方法
2021/04/02 Python
Spring Boot实战解决高并发数据入库之 Redis 缓存+MySQL 批量入库问题
2022/02/12 Redis
Go获取两个时区的时间差
2022/04/20 Golang
windows安装 redis 6.2.6最新步骤详解
2022/04/26 Redis