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 相关文章推荐
第十节 抽象方法和抽象类 [10]
Oct 09 PHP
COM in PHP (winows only)
Oct 09 PHP
php错误提示failed to open stream: HTTP request failed!的完美解决方法
Jun 06 PHP
UCenter 批量添加用户的php代码
Jul 17 PHP
解析左右值无限分类的实现算法
Jun 20 PHP
PHP函数实现分页含文本分页和数字分页
Oct 23 PHP
通过php删除xml文档内容的方法
Jan 23 PHP
利用PHP将部分内容用星号替换
Apr 21 PHP
php微信开发之上传临时素材
Jun 24 PHP
利用laravel搭建一个迷你博客实战教程
Aug 13 PHP
laravel 时间格式转时间戳的例子
Oct 11 PHP
PHP中isset、empty的用法与区别示例详解
Nov 05 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
用PHP调用Oracle存储过程
2006/10/09 PHP
用Zend Encode编写开发PHP程序
2010/02/21 PHP
PHP学习之数组的定义和填充
2011/04/17 PHP
第4章 数据处理-php数组的处理-郑阿奇
2011/07/04 PHP
基于PHP实现的事件机制实例分析
2015/06/18 PHP
JS+PHP实现用户输入数字后显示最大的值及所在位置
2017/06/19 PHP
JS实现从连接中获取youtube的key实例
2015/07/02 Javascript
javascript伸缩菜单栏实现代码分享
2015/11/12 Javascript
轻松学习jQuery插件EasyUI EasyUI创建树形菜单
2015/11/30 Javascript
js动态获取子复选项并设计全选及提交的实现方法
2016/06/24 Javascript
基于jquery实现二级联动效果
2017/03/30 jQuery
vue-quill-editor实现图片上传功能
2017/08/08 Javascript
使用html+js+css 实现页面轮播图效果(实例讲解)
2017/09/21 Javascript
Angularjs Promise实例详解
2018/03/15 Javascript
vue自定义filters过滤器
2018/04/26 Javascript
小程序中英文混合排序问题解决
2019/08/02 Javascript
微信小程序 调用远程接口 给全局数组赋值代码实例
2019/08/13 Javascript
解决layui数据表格排序图标被超出的表头挤出去的问题
2019/09/19 Javascript
[02:44]DOTA2英雄基础教程 克林克兹
2014/01/15 DOTA
[05:35]DOTA2英雄梦之声_第13期_拉比克
2014/06/21 DOTA
python解析文件示例
2014/01/23 Python
详谈Pandas中iloc和loc以及ix的区别
2018/06/08 Python
python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
2019/04/01 Python
Python3.5装饰器原理及应用实例详解
2019/04/30 Python
python下载卫星云图合成gif的方法示例
2020/02/18 Python
捷克街头、运动和滑板一站式商店:BoardStar.cz
2019/10/06 全球购物
广告设计专业自荐信范文
2013/11/14 职场文书
开展党的群众路线教育实践活动方案
2014/02/05 职场文书
爱心活动计划书
2014/04/26 职场文书
收入及婚姻状况证明
2014/11/20 职场文书
文明倡议书
2015/01/19 职场文书
租赁协议书
2015/01/27 职场文书
民主生活会意见
2015/06/05 职场文书
钢琴师观后感
2015/06/12 职场文书
开业典礼致辞
2015/07/29 职场文书
教你一步步实现一个简易promise
2021/11/02 Javascript