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下几种删除目录的方法总结
Aug 19 PHP
常见的PHP五种设计模式小结
Mar 23 PHP
PHP中获取文件扩展名的N种方法小结
Feb 27 PHP
php代码中使用换行及(\n或\r\n和br)的应用
Feb 02 PHP
JavaScript创建命名空间的5种写法
Jun 24 PHP
php curl 上传文件代码实例
Apr 27 PHP
PHP访问数据库集群的方法小结
Mar 14 PHP
实例讲解php数据访问
May 09 PHP
php截取视频指定帧为图片
May 16 PHP
PHP框架Laravel插件Pagination实现自定义分页
Apr 22 PHP
PHP读取大文件末尾N行的高效方法推荐
Jun 03 PHP
分享5个非常有用的Laravel Blade指令
May 30 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网站提速三大“软”招
2006/10/09 PHP
createElement与createDocumentFragment的点点区别小结
2011/12/19 Javascript
JavaScript根据数据生成百分比图和柱状图的实例代码
2013/07/14 Javascript
javascript中Object使用详解
2015/01/26 Javascript
JavaScript基于setTimeout实现计数的方法
2015/05/08 Javascript
基于javascript实现窗口抖动效果
2016/01/03 Javascript
jquery插件jquery.LightBox.js实现点击放大图片并左右点击切换效果(附demo源码下载)
2016/02/25 Javascript
基于JQuery实现图片上传预览与删除操作
2016/05/24 Javascript
微信小程序 数组(增,删,改,查)等操作实例详解
2017/01/05 Javascript
JavaScript实现星级评分
2017/01/12 Javascript
AngularJS中使用ngModal模态框实例
2017/05/27 Javascript
JS写XSS cookie stealer来窃取密码的步骤详解
2017/11/20 Javascript
MUI 实现侧滑菜单及其主体部分上下滑动的方法
2018/01/25 Javascript
JS散列表碰撞处理、开链法、HashTable散列示例
2019/02/08 Javascript
使用Vue.js 和Chart.js制作绚丽多彩的图表
2019/06/15 Javascript
微信小程序判断页面是否从其他页面返回的实例代码
2019/07/03 Javascript
vue中实现上传文件给后台实例详解
2019/08/22 Javascript
Vue看了就会的8个小技巧
2021/01/21 Vue.js
python中使用sys模板和logging模块获取行号和函数名的方法
2014/04/15 Python
python实现simhash算法实例
2014/04/25 Python
python对url格式解析的方法
2015/05/13 Python
更新修改后的Python模块方法
2019/03/03 Python
python程序快速缩进多行代码方法总结
2019/06/23 Python
python如何实现数据的线性拟合
2019/07/19 Python
pytorch1.0中torch.nn.Conv2d用法详解
2020/01/10 Python
python argparse模块通过后台传递参数实例
2020/04/20 Python
Python3中小括号()、中括号[]、花括号{}的区别详解
2020/11/15 Python
美国专注于健康商品的网站:eVitamins
2017/01/23 全球购物
2014年情人节活动方案
2014/02/16 职场文书
党员学习党的群众路线思想汇报(5篇)
2014/09/10 职场文书
行政执法队伍作风整顿个人剖析材料
2014/10/11 职场文书
2015年度保密工作总结
2015/04/24 职场文书
工作年限证明范本
2015/06/15 职场文书
小学生一年级(书信作文)
2019/08/13 职场文书
浅谈Python numpy创建空数组的问题
2021/05/25 Python
总结python多进程multiprocessing的相关知识
2021/06/29 Python