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 相关文章推荐
Ajax实时验证用户名/邮箱等是否已经存在的代码打包
Dec 01 PHP
ThinkPHP 连接Oracle数据库的详细教程[全]
Jul 16 PHP
浅析Dos下运行php.exe,出现没有找到php_mbstring.dll 错误的解决方法
Jun 29 PHP
使用php记录用户通过搜索引擎进网站的关键词
Feb 13 PHP
php数组删除元素示例
Mar 21 PHP
php json_encode()函数返回json数据实例代码
Oct 10 PHP
php数组添加元素方法小结
Dec 20 PHP
PHP实现XML与数据格式进行转换类实例
Jul 29 PHP
PHP将URL转换成短网址的算法分享
Sep 13 PHP
PHP判断用户是否已经登录(跳转到不同页面或者执行不同动作)
Sep 22 PHP
PHP中关于php.ini参数优化详解
Feb 28 PHP
laravel与thinkphp之间的区别与优缺点
Mar 02 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+jquery编码方面的一些心得(utf-8 gb2312)
2010/10/12 PHP
自编函数解决pathinfo()函数处理中文问题
2014/11/03 PHP
PHP实现无限极分类图文教程
2014/11/25 PHP
php发送与接收流文件的方法
2015/02/11 PHP
php脚本运行时的超时机制详解
2016/02/17 PHP
PHP多进程编程总结(推荐)
2016/07/18 PHP
PHP弱类型的安全问题详细总结
2016/09/25 PHP
使用EXT实现无刷新动态调用股票信息
2008/11/01 Javascript
javascript 打印页面代码
2009/03/24 Javascript
input的focus方法使用
2010/03/13 Javascript
Knockout text绑定DOM的使用方法
2013/11/15 Javascript
探讨JavaScript中声明全局变量三种方式的异同
2013/12/03 Javascript
javascript在IE下trim函数无法使用的解决方法
2014/09/12 Javascript
jQuery实现简单二级下拉菜单
2015/04/12 Javascript
Node.js开发者必须了解的4个JS要点
2016/02/21 Javascript
javascript面向对象程序设计高级特性经典教程(值得收藏)
2016/05/19 Javascript
基于jQuery实现仿微博发布框字数提示
2016/07/27 Javascript
JavaScript中const、var和let区别浅析
2016/10/11 Javascript
微信小程序 switch组件详解及简单实例
2017/01/10 Javascript
php简单数据库操作类的封装
2017/06/08 Javascript
js技巧之十几行的代码实现vue.watch代码
2018/06/09 Javascript
浅谈JavaScript_DOM学习篇_图片切换小案例
2019/03/19 Javascript
uniapp电商小程序实现订单30分钟倒计时
2020/11/01 Javascript
python实现KNN分类算法
2019/10/16 Python
Python如何实现感知器的逻辑电路
2020/12/25 Python
thinkphp5 路由分发原理
2021/03/18 PHP
巴西24小时在线药房:Droga Raia
2020/05/12 全球购物
英语道歉信范文
2014/01/09 职场文书
决心书标准格式
2014/03/11 职场文书
怎样填写就业意向
2014/04/02 职场文书
公司采购主管岗位职责
2014/06/17 职场文书
倡议书作文
2015/01/19 职场文书
2015羊年春节慰问信
2015/02/14 职场文书
毕业生入职感言
2015/07/31 职场文书
SqlServer: 如何更改表的文件组?(进而改变存储位置)
2021/04/05 SQL Server
Java 轮询锁使用时遇到问题
2022/05/11 Java/Android