php多进程并发编程防止出现僵尸进程的方法分析


Posted in PHP onFebruary 28, 2020

本文实例讲述了php多进程并发编程防止出现僵尸进程的方法。分享给大家供大家参考,具体如下:

对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题。

僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程。任何进程在退出前(使用exit退出) 都会变成僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多,最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。 

方法一:

父进程通过pcntl_wait和pcntl_waitpid等函数等待子进程结束

$pid = pcntl_fork();

if($pid == -1) {
  die('fork error');
} else if ($pid) {
  //父进程阻塞着等待子进程的退出
  //pcntl_wait($status);

  //pcntl_waitpid($pid, $status);
  
  //非阻塞方式
  //pcntl_wait($status, WNOHANG);

  //pcntl_waitpid($pid, $status, WNOHANG);
} else {
  sleep(3);
  echo "child \r\n";
  exit;
}

方法二:

可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用pcntl_wait或pcntl_waitpid来回收。

<?php
declare(ticks = 1);

//信号处理函数
function sig_func() {
  echo "SIGCHLD \r\n";
  pcntl_wait($status);

  //pcntl_waitpid(-1, $status);

  //非阻塞
  //pcntl_wait($status, WNOHANG);
  //pcntl_waitpid(-1, $status, WNOHANG);
}

pcntl_signal(SIGCHLD, 'sig_func');

$pid = pcntl_fork();

if($pid == -1) {
  die('fork error');
} else if ($pid) {
  sleep(10);
} else {
  sleep(3);
  echo "child \r\n";
  exit;
}

如果子进程还没有结束时,父进程就结束了,那么init进程会自动接手这个子进程,进行回收。

如果父进程是循环,又没有安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束。那么子进程结束后,没有回收,就产生僵尸进程了。 

例如:

<?php
$pid = pcntl_fork();

if($pid == -1) {
  die('fork error');
} else if ($pid) {
  for(;;) {
    sleep(3);
  }
} else {
  echo "child \r\n";
  exit;
}

父进程是个死循环,也没有安装SIGCHLD信号处理函数,子进程结束后。我们通过如下命令查看

> ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

会发现一个僵尸进程。 

代码改进一下:

<?php
declare(ticks = 1);

//信号处理函数
function sig_func() {
  echo "SIGCHLD \r\n";

  pcntl_waitpid(-1, $status, WNOHANG);
}

pcntl_signal(SIGCHLD, 'sig_func');

$pid = pcntl_fork();

if($pid == -1) {
  die('fork error');
} else if ($pid) {
  for(;;) {
    sleep(3);
  }
} else {
  echo "child \r\n";
  exit;
}

当子进程结束后,再通过命令查看时,我们发现这时就没有僵尸进程了,这说明父进程对它进行了回收。 

方法三:

如果父进程不关心子进程什么时候结束,那么可以用pcntl_signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号。

<?php
declare(ticks = 1);

pcntl_signal(SIGCHLD, SIG_IGN);

$pid = pcntl_fork();

if($pid == -1) {
  die('fork error');
} else if ($pid) {
  for(;;) {
    sleep(3);
  }
} else {
  echo "child \r\n";
  exit;
}

当子进程结束后,SIGCHLD信号并不会发送给父进程,而是通知内核对子进程进行了回收。 

方法四:

通过pcntl_fork两次,也就是父进程fork出子进程,然后子进程中再fork出孙进程,这时子进程退出。那么init进程会接管孙进程,孙进程退出后,init会回收。不过子进程还是需要父进程进行回收。我们把业务逻辑放到孙进程中执行,父进程就不需要pcntl_wait或pcntl_waitpid来等待孙进程(即业务进程)。

<?php
$pid = pcntl_fork();

if($pid == -1) {
  die('fork error');
} else if ($pid) {
  //父进程等待子进程退出
  pcntl_wait($status);
  echo "parent \r\n";
} else {
  //子进程再fork一次,产生孙进程
  $cpid = pcntl_fork();  
  if($cpid == -1) {
    die('fork error');
  } else if ($cpid) {
    //这里是子进程,直接退出
    echo "child \r\n";
    exit;
  } else {
    //这里是孙进程,处理业务逻辑
    for($i = 0; $i < 10; ++$i) {
      echo "work... \r\n";
      sleep(3);
    }
  }
}

子进程退出后,父进程回收子进程,孙进程继续业务逻辑的处理。当孙进程也执行完毕退出后,init回收孙进程。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP学习笔记 (1) 环境配置与代码调试
Jun 19 PHP
解析PHP对现有搜索引擎的调用
Jun 25 PHP
php中把美国时间转为北京时间的自定义函数分享
Jul 28 PHP
destoon调用discuz论坛中带图片帖子的实现方法
Aug 21 PHP
PHP遍历XML文档所有节点的方法
Mar 12 PHP
PHP读取配置文件类实例(可读取ini,yaml,xml等)
Jul 28 PHP
PHP执行SQL文件并将SQL文件导入到数据库
Sep 17 PHP
10个超级有用的PHP代码片段果断收藏
Sep 23 PHP
详解Yii实现分页的两种方法
Jan 14 PHP
PHP实现简单的模板引擎功能示例
Sep 02 PHP
Laravel Eloquent ORM 多条件查询的例子
Oct 10 PHP
php双向队列实例讲解
Nov 17 PHP
php 的多进程操作实践案例分析
Feb 28 #PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
Feb 28 #PHP
php的无刷新操作实现方法分析
Feb 28 #PHP
php下的原生ajax请求用法实例分析
Feb 28 #PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
Feb 27 #PHP
php使用fputcsv实现大数据的导出操作详解
Feb 27 #PHP
gearman中任务的优先级和返回状态实例分析
Feb 27 #PHP
You might like
上海地方志办公室-上海电子仪表工业志
2021/03/04 无线电
Apache环境下PHP利用HTTP缓存协议原理解析及应用分析
2010/02/16 PHP
php Imagick获取图片RGB颜色值
2014/07/28 PHP
php如何获取文件的扩展名
2015/10/28 PHP
Laravel5.5 动态切换多语言的操作方式
2019/10/25 PHP
超清晰的document对象详解
2007/02/27 Javascript
让iframe子窗体取父窗体地址栏参数(querystring)
2009/10/13 Javascript
JS模拟面向对象全解(一、类型及传递)
2011/07/13 Javascript
jquery.qrcode在线生成二维码使用示例
2013/08/21 Javascript
js的隐含参数(arguments,callee,caller)使用方法
2014/01/28 Javascript
jQuery超酷平面式时钟效果代码分享
2020/03/30 Javascript
日常收藏的jquery技巧
2015/12/02 Javascript
Node.js开发者必须了解的4个JS要点
2016/02/21 Javascript
jQuery中each()、find()和filter()等节点操作方法详解(推荐)
2016/05/25 Javascript
Javascript中函数名.length属性用法分析(对比arguments.length)
2016/09/16 Javascript
easyui form validate总是返回false的原因及解决方法
2016/11/07 Javascript
vue2利用Bus.js如何实现非父子组件通信详解
2017/08/25 Javascript
JS通过位运算实现权限加解密
2018/08/14 Javascript
js实现烟花特效
2020/03/02 Javascript
Python编写简单的HTML页面合并脚本
2016/07/11 Python
python paramiko模块学习分享
2017/08/23 Python
浅谈PYTHON 关于文件的操作
2019/03/19 Python
解决pycharm最左侧Tool Buttons显示不全的问题
2019/12/17 Python
利用PyTorch实现VGG16教程
2020/06/24 Python
Python关于拓扑排序知识点讲解
2021/01/04 Python
法学毕业生自我鉴定
2013/11/08 职场文书
幼儿园家长会欢迎词
2014/01/09 职场文书
房地产项目策划书
2014/02/05 职场文书
城市精细化管理实施方案
2014/03/04 职场文书
农村文化活动总结
2014/08/28 职场文书
地理科学专业自荐信
2014/09/01 职场文书
办理信用卡收入证明范例
2014/09/13 职场文书
运动会广播稿150字(9篇)
2014/09/20 职场文书
清洁员岗位职责
2015/02/15 职场文书
2016学习医德医风心得体会
2016/01/25 职场文书
pandas中对文本类型数据的处理小结
2021/11/01 Python