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之第二天
Oct 09 PHP
php 数组的合并、拆分、区别取值函数集
Feb 15 PHP
QueryPath PHP 中的jQuery
Apr 11 PHP
使用PHP实现Mysql读写分离
Jun 28 PHP
php 模拟 asp.net webFrom 按钮提交事件的思路及代码
Dec 02 PHP
php url路由入门实例
Apr 23 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
Aug 11 PHP
在WordPress中使用wp-cron插件来设置定时任务
Dec 10 PHP
PHP结合Mysql数据库实现留言板功能
Mar 04 PHP
使用php实现网站验证码功能【推荐】
Feb 09 PHP
PHP实现的MD5结合RSA签名算法实例
Oct 07 PHP
PHP的RSA加密解密方法以及开发接口使用
Feb 11 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 adodb分页实现代码
2009/03/19 PHP
PHP中file_exists与is_file,is_dir的区别介绍
2012/09/12 PHP
Windows中使用计划任务自动执行PHP程序实例
2014/05/09 PHP
客户端静态页面玩分页
2006/06/26 Javascript
自适应图片大小的弹出窗口
2006/07/27 Javascript
Javascript拓展String方法小结
2013/07/08 Javascript
一个html5播放视频的video控件只支持android的默认格式mp4和3gp
2014/05/08 Javascript
js实现的点击div区域外隐藏div区域
2014/06/30 Javascript
jquery 操作css样式、位置、尺寸方法汇总
2014/11/28 Javascript
jQuery仿gmail实现fixed布局的方法
2015/05/27 Javascript
javascript中select下拉框的用法总结
2016/01/07 Javascript
javascript使用闭包模拟对象的私有属性和方法
2016/10/05 Javascript
JavaScript登录验证码的实现
2016/10/27 Javascript
vue2项目使用sass的示例代码
2017/06/28 Javascript
AngularJS动态添加数据并删除的实例
2018/02/27 Javascript
解决vue单页使用keep-alive页面返回不刷新的问题
2018/03/13 Javascript
使用angularjs.foreach时return的问题解决
2018/09/30 Javascript
浅谈vue加载优化策略
2019/03/19 Javascript
webpack4 从零学习常用配置(小结)
2019/05/28 Javascript
[43:47]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#2 MVP.Phx VS Fnatic第一局
2016/03/05 DOTA
[09:47]2018DOTA2亚洲邀请赛4.5SOLO赛 No[o]ne vs Sumail
2018/04/06 DOTA
[01:17:47]TNC vs VGJ.S 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
SQLite3中文编码 Python的实现
2017/01/11 Python
python中的二维列表实例详解
2018/06/19 Python
python中文编码与json中文输出问题详解
2018/08/24 Python
谈谈Python中的while循环语句
2019/03/10 Python
python 实现分组求和与分组累加求和代码
2020/05/18 Python
python实现凯撒密码、凯撒加解密算法
2020/06/11 Python
区分python中的进程与线程
2020/08/13 Python
奥地利时尚、美容、玩具和家居之家:Kastner & Öhler
2020/04/26 全球购物
考核工作实施方案
2014/03/30 职场文书
个人担保书格式范文
2014/05/12 职场文书
市级优秀班主任事迹材料
2014/05/13 职场文书
文明和谐家庭事迹材料
2014/05/18 职场文书
小学教师师德师风自我评价
2015/03/04 职场文书
MySQL多表查询机制
2022/03/17 MySQL