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初学者头疼问题总结
Jul 08 PHP
基于mysql的论坛(1)
Oct 09 PHP
PHP安装攻略:常见问题解答(一)
Oct 09 PHP
php中常量DIRECTORY_SEPARATOR用法深入分析
Nov 14 PHP
PHP数组和explode函数示例总结
May 08 PHP
php有效防止图片盗用、盗链的两种方法
Nov 01 PHP
PHP迭代与递归实现无限级分类
Aug 28 PHP
PHP chunk_split()函数讲解
Feb 12 PHP
PHP使用Redis实现Session共享的实现示例
May 12 PHP
PHP面向对象类型约束用法分析
Jun 12 PHP
Laravel Eloquent分表方法并使用模型关联的实现
Nov 25 PHP
Laravel中获取IP的真实地理位置
Apr 01 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实现的一个很好用HTML解析器类可用于采集数据
2013/09/23 PHP
PHP redis实现超迷你全文检索
2017/03/04 PHP
Laravel 集成微信用户登录和绑定的实现
2019/12/27 PHP
超轻量级的基于jquery的三级展开列表
2011/04/26 Javascript
js 控制页面跳转的5种方法
2013/09/09 Javascript
jquery使用slideDown实现模块缓慢拉出效果的方法
2015/03/27 Javascript
Js+php实现异步拖拽上传文件
2015/06/23 Javascript
微信QQ的二维码登录原理js代码解析
2016/06/23 Javascript
详解vue.js全局组件和局部组件
2017/04/10 Javascript
Bootstrap模态框插件使用详解
2017/05/11 Javascript
基于Vue实现页面切换左右滑动效果
2020/06/29 Javascript
jQuery+HTML5实现WebGL高性能烟花绽放动画效果【附demo源码下载】
2017/08/18 jQuery
jqueryUI tab标签页代码分享
2017/10/09 jQuery
微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
2018/10/12 Javascript
详解webpack+ES6+Sass搭建多页面应用
2018/11/05 Javascript
用Python制作检测Linux运行信息的工具的教程
2015/04/01 Python
Python简单实现安全开关文件的两种方式
2016/09/19 Python
Python 内置函数memoryview(obj)的具体用法
2017/11/23 Python
python实现雨滴下落到地面效果
2018/06/21 Python
python程序变成软件的实操方法
2019/06/24 Python
基于Pytorch SSD模型分析
2020/02/18 Python
浅谈python累加求和+奇偶数求和_break_continue
2020/02/25 Python
Python过滤掉numpy.array中非nan数据实例
2020/06/08 Python
简单了解Python变量作用域正确使用方法
2020/06/12 Python
Python如何读写二进制数组数据
2020/08/01 Python
Django使用django-simple-captcha做验证码的实现示例
2021/01/07 Python
HTML5 Web 存储详解
2016/09/16 HTML / CSS
安德玛比利时官网:Under Armour比利时
2019/08/28 全球购物
一套比较完整的软件测试人员面试题
2012/05/13 面试题
在职研究生自我鉴定
2013/10/16 职场文书
优秀毕业生求职信
2014/06/05 职场文书
国际会计专业求职信
2014/08/04 职场文书
五好家庭申报材料
2014/12/20 职场文书
反腐倡廉主题教育活动总结
2015/05/07 职场文书
大学三好学生主要事迹范文
2015/11/03 职场文书
详解Python为什么不用设计模式
2021/06/24 Python