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实现用户认证及管理完全源码
Mar 11 PHP
php中将地址生成迅雷快车旋风链接的代码[测试通过]
Apr 20 PHP
PHP备份数据库生成SQL文件并下载的函数代码
Feb 05 PHP
php调用C代码的实现方法
Mar 11 PHP
PHP解密Unicode及Escape加密字符串
May 17 PHP
如何解决phpmyadmin导入数据库文件最大限制2048KB
Oct 09 PHP
php实现文件上传及头像预览功能
Jan 15 PHP
thinkphp项目如何自定义微信分享描述内容
Feb 20 PHP
PHP实现ASCII码与字符串相互转换的方法
Apr 29 PHP
利用laravel+ajax实现文件上传功能方法示例
Aug 13 PHP
PHP利用Mysql锁解决高并发的方法
Sep 04 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遍历类中包含的所有元素的方法
2015/05/12 PHP
[原创]php逐行读取txt文件写入数组的方法
2015/07/02 PHP
PHP 中 Orientation 属性判断上传图片是否需要旋转
2015/10/16 PHP
Thinkphp微信公众号支付接口
2016/08/04 PHP
phpstudy后门rce批量利用脚本的实现
2019/12/12 PHP
JavaScript 加号(+)运算符号
2009/12/06 Javascript
Bookmarklet实现启动jQuery(模仿 云输入法)
2010/09/15 Javascript
JS获取图片实际宽高及根据图片大小进行自适应
2013/08/11 Javascript
JavaScript如何实现组合列表框中元素移动效果
2016/03/01 Javascript
JSON 的正确用法探讨:Pyhong、MongoDB、JavaScript与Ajax
2016/05/15 Javascript
Jquery把获取到的input值转换成json
2017/05/15 jQuery
关于使用js算总价的问题
2017/06/23 Javascript
Vue不能检测到Object/Array更新的情况的解决
2018/06/26 Javascript
koa-passport实现本地验证的方法示例
2020/02/20 Javascript
js实现简单进度条效果
2020/03/25 Javascript
使用python实现拉钩网上的FizzBuzzWhizz问题示例
2014/05/05 Python
在Python3中使用asyncio库进行快速数据抓取的教程
2015/04/02 Python
Python爬虫的两套解析方法和四种爬虫实现过程
2018/07/20 Python
python实现小球弹跳效果
2019/05/10 Python
PyQt QListWidget修改列表项item的行高方法
2019/06/20 Python
Python 虚拟环境工作原理解析
2020/12/24 Python
python线程优先级队列知识点总结
2021/02/28 Python
全面解析CSS Media媒体查询使用操作(推荐)
2017/08/15 HTML / CSS
Marriott中国:万豪国际酒店查询预订
2016/09/02 全球购物
澳大利亚现代波西米亚风格女装网站:Bohemian Traders
2018/04/16 全球购物
美国在线工具商店:Acme Tools
2018/06/26 全球购物
农行实习自我鉴定
2013/09/22 职场文书
财务管理个人自荐书范文
2013/11/24 职场文书
历史专业个人求职信范文
2013/12/07 职场文书
质量承诺书格式
2014/05/20 职场文书
体育馆的标语
2014/06/24 职场文书
应届生面试求职信
2014/07/02 职场文书
费用申请报告范文
2015/05/15 职场文书
应届生们该怎么书写求职信?
2019/07/05 职场文书
Django 如何实现文件上传下载
2021/04/08 Python
科学家测试在太空中培育人造肉,用于未来太空旅行
2022/04/29 数码科技