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&amp;java(二)
Oct 09 PHP
一键删除顽固的空文件夹 软件下载
Jan 26 PHP
56.com视频采集接口程序(PHP)
Sep 22 PHP
Fatal error: Call to undefined function curl_init()解决方法
Apr 09 PHP
php解压文件代码实现php在线解压
Feb 13 PHP
php自动识别文件编码并转换为UTF-8的方法
Jun 12 PHP
Yii净化器CHtmlPurifier用法示例(过滤不良代码)
Jul 15 PHP
CI框架实现优化文件上传及多文件上传的方法
Jan 04 PHP
详解php中的implements 使用
Jun 13 PHP
PHP实现用户异地登录提醒功能的方法【基于thinkPHP框架】
Mar 15 PHP
PHP实现浏览器格式化显示XML的方法示例
Jan 22 PHP
laravel 解决路由除了根目录其他都404的问题
Oct 18 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 使用file_get_contents读取大文件的方法
2014/11/13 PHP
CentOS 安装 PHP5.5+Redis+XDebug+Nginx+MySQL全纪录
2015/03/25 PHP
如何解决phpmyadmin导入数据库文件最大限制2048KB
2015/10/09 PHP
PHP切割汉字的常用方法实例总结
2019/04/27 PHP
一款js和css代码压缩工具[附JAVA环境配置方法]
2010/04/16 Javascript
javascript与cookie 的问题详解
2013/11/11 Javascript
浅析jQuery中调用ajax方法时在不同浏览器中遇到的问题
2014/06/11 Javascript
json字符串之间的相互转换示例代码
2014/08/21 Javascript
js制作简易年历完整实例
2015/01/28 Javascript
jquery实现动静态条形统计图
2015/08/17 Javascript
JavaScript使用DeviceOne开发实战(二) 生成调试安装包
2015/12/01 Javascript
让你彻底掌握es6 Promise的八段代码
2017/07/26 Javascript
[原创]js实现保存文本框内容为本地文件兼容IE,chrome,火狐浏览器
2018/02/14 Javascript
浅析Vue项目中使用keep-Alive步骤
2018/07/27 Javascript
vue3.0 CLI - 3.2 路由的初级使用教程
2018/09/20 Javascript
跟老齐学Python之重回函数
2014/10/10 Python
详解Python import方法引入模块的实例
2017/08/02 Python
Python使用matplotlib简单绘图示例
2018/02/01 Python
cmd运行python文件时对结果进行保存的方法
2018/05/16 Python
Selenium定位元素操作示例
2018/08/10 Python
Python matplotlib以日期为x轴作图代码实例
2019/11/22 Python
解决Tensorboard可视化错误:不显示数据 No scalar data was found
2020/02/15 Python
python Socket网络编程实现C/S模式和P2P
2020/06/22 Python
Python使用xlrd实现读取合并单元格
2020/07/09 Python
美国流行背包品牌:JanSport(杰斯伯)
2018/03/02 全球购物
爱尔兰电子产品购物网站:Komplett.ie
2018/04/04 全球购物
亚马逊巴西站:Amazon.com.br
2019/09/22 全球购物
如何在存储过程中使用Loop
2016/01/05 面试题
申请任职学生会干部自荐书范文
2014/02/13 职场文书
幼儿园毕业教师感言
2014/02/21 职场文书
学雷锋志愿者活动总结
2014/06/27 职场文书
学校中层领导培训心得体会
2016/01/11 职场文书
企业文化学习心得体会
2016/01/21 职场文书
Nginx location 和 proxy_pass路径配置问题小结
2021/09/04 Servers
MyBatis-Plus 批量插入数据的操作方法
2021/09/25 Java/Android
详解Python+OpenCV绘制灰度直方图
2022/03/22 Python