PHP多进程之pcntl_fork的实例详解


Posted in PHP onOctober 15, 2017

PHP多进程编之pcntl_fork的实例详解

其实PHP是支持并发的,只是平时很少使用而已。平时使用最多的应该是使用PHP-FMP调度php进程了吧。

但是,PHP的使用并不局限于做Web,我们完全也可以使用PHP来进行系统工具类的编程,做监控或者是运维。在使用这些方向的时候,我们可以使用到PHP的更多特性,例如并发(多进程)、socket编程等。

那么接下来就说说我遇到的PHP多进程的编程。这个多进程的使用是有一个背景的,下面模糊描述一下背景。

我需要一个监控系统,当然使用PHP语言,监控系统需要监控很多种系统指标,为了让每个监控指标之间尽量专心的去做自己的事情,就需要单独使用一个进程去监控一个指标,还有一个进程去读取配置,拿到配置之后,根据配置去启动每条进程。

那么,这就需要我所说的多进程了。

  1. 首先启动一个主进程,主进程用来读取配置信息。例如,我读取到了我需要监控5个指标
  2. 接下来主进程启动5个子进程,分别监控这5个指标。
  3. 创建好5个指标监控进程之后之后,主进程进行监听配置。
  4. 一旦配置发生改变,杀死之前的进程并重新创建进程。

相对来说比较清晰的逻辑。那么接下来我们就化简一下操作:简单的说就是一个主进程创建5个子进程。

首先,创建进程在需要使用php的一个函数pcntl_fork(),这个函数可能有的同学不太熟,不过接触过Linux C变成的人都知道Linux下有个叫fork()的函数,用来创建子进程。这个函数和Linux下这个函数是一个意思。需要注意的是,这个函数在Linux下才能使用,而且需要安装pcntl的扩展。

对于这个函数怎么使用,我们可以查阅官方文档:http://php.net/manual/zh/function.pcntl-fork.php

官方文档是这样说的:

pcntl_fork()函数创建一个子进程,这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同。fork怎样在您的系统工作的详细信息请查阅您的系统 的fork(2)手册。

成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。

这样就可以创建一个子进程了,子进程创建成功以后会执行pcntl_fork()之后的方法。那么对于这个函数的返回值我们如何理解呢?

是这样的,我们调用函数创建进程的时候,函数执行时有时间的,而新的进程刚好是在函数执行开始和结束之间创建出来的,这样,新的进程也执行了这个函数,所以函数也需要有返回值。那么对于该函数一次执行之后,父进程和子进程都会受到该函数的返回值,由于父进程创建了子进程,而子进程并没有创建新的进程,所以子进程对于这个函数的返回结果是没有的,所以就给他赋了一个0。而父进程创建了子进程,子进程是存在pid的,所以就得到了那个进程的pid。

我们可以写个程序了解一下:

$pid = pcntl_fork();
var_dump($pid);

这个调用会输出两个值,但是我们如果直接print的只能看到一个值,也就是子进程的pid,但是使用var_dump我们就可以看到两个值,是0和子进程的pid。0这个值就是子进程返回过来的。

那么如何创建进程了解清楚之后,就可以开始创建进程了,我们需要创建5个进程,那么我就循环5次创建进程。得到如下代码:

$i=0;
 while($i!=5){
  $pid = pcntl_fork();
  echo $pid."---------hahah".$i++.PHP_EOL;
 }

这样就写好了,那么运行一下吧。啊?发现不是5个进程啊,发现有好多个进程,而且最后一个hahah4这个输出有32个,为什么是32呢?我们算一算。2^5=32,为什么最后的线程数以指数增长了呢?

想发现这个并不难,因为我们之后的每一条都执行了while循环,到最后成了进程的指数增长——也就是说fork的时候把while循环也带了进去。但是我们只是要5个进程而已。怎么办呢?

通过之前对函数的研究可以看到,子进程中会返回一个为0的值,那么我们就可以知道,0为子进程的标记。我们可以通过对子进程标记来结束进程执行。所以我们可以将我们的代码修改为如下形式:

$i=0;
while($i!=5){
 $pid = pcntl_fork();
 echo $pid."---------hahah".$i++.PHP_EOL;
 if ($pid == 0) {
  echo "子进程".PHP_EOL;
  return;
 }
}

因为0其实是对子进程的标记,那么pid这个变量在子进程里实际上是0的,所以当发现pid的值为0的时候,我们就可以断定我们当前进程为一个子进程,不需要在让他执行while并创建子进程的子进程了,所以在执行完我们的内容之后就return或者exit退出这个执行就好了。这样就能保证我们执行创建了5个进程而不是32个了。

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

PHP 相关文章推荐
PHP下操作Linux消息队列完成进程间通信的方法
Jul 24 PHP
php表单请求获得数据求和示例
May 15 PHP
教你如何在CI框架中使用 .htaccess 隐藏url中index.php
Jun 09 PHP
php5.3不能连接mssql数据库的解决方法
Dec 27 PHP
Laravel5中contracts详解
Mar 02 PHP
php编写批量生成不重复的卡号密码代码
May 14 PHP
PHP消息队列用法实例分析
Feb 12 PHP
PHP中key和current,next的联合运用实例分析
Mar 29 PHP
YII框架批量插入数据的方法
Mar 18 PHP
php实现数组纵向转横向并过滤重复值的方法分析
May 29 PHP
[原创]PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】
Jul 12 PHP
laravel框架中视图的基本使用方法分析
Nov 23 PHP
详解thinkphp5+swoole实现异步邮件群发(SMTP方式)
Oct 13 #PHP
详解PHP字符串替换str_replace()函数四种用法
Oct 13 #PHP
浅谈PHP接入(第三方登录)QQ登录 OAuth2.0 过程中遇到的坑
Oct 13 #PHP
PHP长网址与短网址的实现方法
Oct 13 #PHP
如何直接访问php实例对象中的private属性详解
Oct 12 #PHP
thinkphp中的多表关联查询的实例详解
Oct 12 #PHP
laravel 5异常错误:FatalErrorException in Handler.php line 38的解决
Oct 12 #PHP
You might like
SONY ICF-SW07收音机电路分析
2021/03/02 无线电
thinkphp中空模板与空模块的用法实例
2014/11/26 PHP
PHP中两个float(浮点数)比较实例分析
2015/09/27 PHP
php使用gd2绘制基本图形示例(直线、圆、正方形)
2017/02/15 PHP
PHP实现json_decode不转义中文的方法
2017/05/20 PHP
浅谈addEventListener和attachEvent的区别
2016/07/14 Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
2016/11/05 Javascript
基于JavaScript+HTML5 实现打地鼠小游戏逻辑流程图文详解(附完整代码)
2017/11/02 Javascript
node.js基于fs模块对系统文件及目录进行读写操作的方法详解
2017/11/10 Javascript
Vue 中批量下载文件并打包的示例代码
2017/11/20 Javascript
Webpack框架核心概念(知识点整理)
2017/12/22 Javascript
浅谈Vue响应式(数组变异方法)
2018/05/07 Javascript
JavaScript 中的 this 工作原理
2018/06/20 Javascript
傻瓜式解读koa中间件处理模块koa-compose的使用
2018/10/30 Javascript
一份超级详细的Vue-cli3.0使用教程【推荐】
2018/11/15 Javascript
vue3.0中setup使用(两种用法)
2020/12/02 Vue.js
Vue组件简易模拟实现购物车
2020/12/21 Vue.js
原生JavaScript实现进度条
2021/02/19 Javascript
[01:06] DOTA2英雄背景故事第三期之秩序法则光之守卫
2020/07/07 DOTA
Python使用getpass库读取密码的示例
2017/10/10 Python
linux环境下的python安装过程图解(含setuptools)
2017/11/22 Python
Python实现的购物车功能示例
2018/02/11 Python
神经网络(BP)算法Python实现及应用
2018/04/16 Python
python Tcp协议发送和接收信息的例子
2019/07/22 Python
Django框架视图层URL映射与反向解析实例分析
2019/07/29 Python
pycharm 批量修改变量名称的方法
2019/08/01 Python
使用虚拟环境打包python为exe 文件的方法
2019/08/29 Python
python3获取url文件大小示例代码
2019/09/18 Python
Python networkx包的实现
2020/02/14 Python
HTML5实践-图片设置成灰度图
2012/11/12 HTML / CSS
Tessabit日本:集世界奢侈品和设计师品牌的意大利精品买手店
2020/01/07 全球购物
办公文员的工作岗位职责
2013/11/12 职场文书
实习自我评价怎么写
2013/12/02 职场文书
自我鉴定三原则
2014/01/13 职场文书
致裁判员加油稿
2014/02/08 职场文书
2014年司法局工作总结
2014/12/11 职场文书