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 相关文章推荐
一个域名查询的程序
Oct 09 PHP
php中防止恶意刷新页面的代码小结
Oct 31 PHP
利用PHP扩展vld查看PHP opcode操作步骤
Mar 04 PHP
phpphp图片采集后按原路径保存图片示例
Feb 18 PHP
php中动态修改ini配置
Oct 14 PHP
Linux平台php命令行程序处理管道数据的方法
Nov 10 PHP
PHP实现基于回溯法求解迷宫问题的方法详解
Aug 17 PHP
PHP判断json格式是否正确的实现代码
Sep 20 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
Jun 14 PHP
浅谈PHP各环境下的伪静态配置
Mar 13 PHP
PHP defined()函数的使用图文详解
Jul 20 PHP
PHP Swoole异步Redis客户端实现方法示例
Oct 24 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
Syphon 秘笈
2021/03/03 冲泡冲煮
用PHP实现文件上传二法
2006/10/09 PHP
Yii查询生成器(Query Builder)用法实例教程
2014/09/04 PHP
php JWT在web端中的使用方法教程
2018/09/06 PHP
jquery autocomplete自动完成插件的的使用方法
2010/08/07 Javascript
JS cookie中文乱码解决方法
2014/01/28 Javascript
jQuery中用dom操作替代正则表达式
2014/12/29 Javascript
详解vue表单验证组件 v-verify-plugin
2017/04/19 Javascript
Vue组件和Route的生命周期实例详解
2018/02/10 Javascript
jquery动态添加带有样式的HTML标签元素方法
2018/02/24 jQuery
vue中axios解决跨域问题和拦截器的使用方法
2018/03/07 Javascript
vue组件实现可搜索下拉框扩展
2020/10/23 Javascript
基于Vue-Cli 打包自动生成/抽离相关配置文件的实现方法
2018/12/09 Javascript
create-react-app中添加less支持的实现
2019/11/15 Javascript
vuex管理状态仓库使用详解
2020/07/29 Javascript
如何利用JavaScript编写一个格斗小游戏
2021/01/06 Javascript
[03:51]吞吞映像 每周精彩击杀top10第二弹
2014/06/25 DOTA
Python 文件重命名工具代码
2009/07/26 Python
Python表示矩阵的方法分析
2017/05/26 Python
Python实现的基数排序算法原理与用法实例分析
2017/11/23 Python
mac安装scrapy并创建项目的实例讲解
2018/06/13 Python
python实现textrank关键词提取
2018/06/22 Python
简单了解python的内存管理机制
2019/07/08 Python
Django多数据库的实现过程详解
2019/08/01 Python
画pytorch模型图,以及参数计算的方法
2019/08/17 Python
opencv3/Python 稠密光流calcOpticalFlowFarneback详解
2019/12/11 Python
python实现时间序列自相关图(acf)、偏自相关图(pacf)教程
2020/06/03 Python
CSS3属性box-shadow使用指南
2014/12/09 HTML / CSS
html5通过canvas实现刮刮卡效果示例分享
2014/01/27 HTML / CSS
公司领导推荐信
2013/11/12 职场文书
2014国培学习感言
2014/03/05 职场文书
敬老月活动总结
2014/08/28 职场文书
个人剖析材料范文
2014/09/30 职场文书
全国法制宣传日活动总结2014
2014/11/01 职场文书
爱晚亭导游词
2015/02/09 职场文书
tp5使用layui实现多个图片上传(带附件选择)的方法实例
2021/11/17 PHP