PHP的多进程--防止僵尸进程(转)
原文地址:http://twei.site/2017/08/08/PHP%E7%9A%84%E5%A4%9A%E8%BF%9B%E7%A8%8B-%E9%98%B2%E6%AD%A2%E5%83%B5%E5%B0%B8%E8%BF%9B%E7%A8%8B/
正文
多进程编码中,一个不得不注意的问题就是僵尸进程(zombie process)。在 PHP 的多进程编码中,也是如此。
什么是僵尸进程
僵尸进程:一个进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait() 或 waitpid() 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这类子进程被称为僵尸进程。
我们详细理解下,在 UNIX/Linux 中,正常情况下,子进程是通过 fork 父进程创建的。子进程和父进程的运行是一个异步过程,理论上父进程无法知道子进程的运行状态。
但知道子进程运行状态是一个很合理的需求,所以 UNIX 提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息,就可以得到。
这种机制就是: 在每个进程退出的时候,内核释放该进程的一部分资源,包括打开的文件、占用的内存等,同时仍然为其保留一定的信息(包括进程号 the process ID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process等)。父进程可以通过 wait()/waitpid() 来获取这些信息,然后操作系统才释放。
这样就产生了一个问题,如果父进程不调用 wait()/waitpid() 的话,那么保留的信息就不会释放,其进程号就会一直被占用,就像僵尸一样,所以把这些进程称为僵尸进程。
僵尸进程的坏处
上面说到僵尸进程由于父进程不回收系统保留的信息而一直占用着系统资源,其中有一项叫做进程描述符。系统通过分配它来启动一个进程。
但是系统所能使用的进程号是有限的,如果存在大量的僵尸进程,系统将因为没有可用的进程号而导致系统不能产生新的进程。
如何查看僵尸进程
僵尸进程在系统中用 <defunct> 或 <z> 表示,通过 ps -ef 指令查看进程,如果发现某个进程的状态为 <defunct>/<z>,说明该进程是一个僵尸进程。

避免僵尸进程的方法
通过WAIT/WAITPID系统
在 pcntl 中,父进程可以通过 pcntl_wait() 和 pcntl_waitpid() 函数来等待子进程结束,并回收。
<?php
$pid = pcntl_fork(); if($pid == -1) {
die('fork error');
}elseif($pid) {
// 父进程阻塞着等待子进程的退出
pcntl_wait($status);
//pcntl_waitpid($pid, $status); // 非阻塞方式,通过WNOHANG区分
//pcntl_wait($status, WNOHANG);
//pcntl_waitpid($pid, $status, WNOHANG); // 如没有上面的函数,在父进程sleep的时候,子进程就是僵尸进程
sleep(10);
}else{
echo "child \r\n";
exit;
}
?>
int pcntl_wait ( int &$status [, int $options ] ):阻塞当前进程,直到当前进程的一个子进程退出或者收到一个结束当前进程的信号。
int pcntl_waitpid ( int $pid , int &$status [, int $options ] ):功能同 pcntl_wait,区别为 waitpid 为等待指定 pid 的子进程。当 pid 为 -1 时 pcntl_waitpid 与 pcntl_wait 一样。
阻塞:父进程一直等待,直到收到一个子进程结束的信号再执行; 非阻塞:父进程和子进程同时执行,不用等子进程执行完。在子进程退出后,再回收。
通过SIGCHLD信号
当子进程结束后,系统会像父进程发送 SIGCHLD 信号给父进程,通知父进程子进程已经结束,但父进程默认不处理。我们可以在父进程收到这个信号时调用 wait()/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');
}elseif($pid) {
// 父进程一直执行
while(1) {
sleep(5);
}
}else{
echo "child \r\n";
exit;
}
在子进程退出后,父进程收到了 SIGCHLD 信号,回调了 sig_func 函数,在内部执行了 pcntl_wait 函数,回收了子进程。
通过操作系统信号
如果父进程不关心子进程什么时候结束,那么可以用 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;
}
PHP的多进程--防止僵尸进程(转)的更多相关文章
- Linux 网络编程详解六(多进程服务器僵尸进程解决方案)
小结:在点对点p2p程序中,服务器端子程序退出,子进程会主动发送信号,关闭父进程,但是这种模式导致服务器只能支持一个客户端连接,本章节中使用新的框架,子进程退出,不主动发送信号关闭父进程,而是父进程安 ...
- PHP多进程编之僵尸进程问题
上一篇说到了使用pcntl_fork函数可以让PHP实现多进程并发或者异步处理的效果.那么问题是我们产生的进程需要去控制,而不能置之不理.最基本的方式就是fork进程和杀死进程. 通过利用pcntl_ ...
- php多进程pcntl学习-僵尸进程
上个月写的文章,php多进程pcntl学习(一)现在发现并不完整,因为虽然提到了关闭子进程,但是并没有回收子进程,简单的说就是当子进程比父进程先退出,而父进程没对其做任何处理的时候,子进程将会变成僵尸 ...
- PHP多进程编程之僵尸进程问题
上一篇说到了使用pcntl_fork函数可以让PHP实现多进程并发或者异步处理的效果.那么问题是我们产生的进程需要去控制,而不能置之不理.最基本的方式就是fork进程和杀死进程. 通过利用pcntl_ ...
- php多进程 防止出现僵尸进程
对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题. 僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程.任何进程在退出前(使用exit退出) ...
- php多进程防止出现僵尸进程
对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题. 僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程.任何进程在退出前(使用exit退出) ...
- 多进程wait、僵尸进程、孤儿进程、prctl
1.概念 1.孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,从而保证每个进程都会有一个父进程.而Init进程会自 ...
- python学习笔记—— 多进程中的 孤儿进程和僵尸进程
1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调 ...
- C/C++网络编程8——多进程服务器端之销毁僵尸进程
上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值. 销毁僵尸进程的方法: 1:使用wait函数 2:使用wait ...
随机推荐
- JAVA_Class.forName
Class.forName(xxx.xx.xx) 返回的是一个类 ,作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段 --------- 首先,在java里面任何class都要 ...
- 1.ossutil初步使用
ossutil对应的阿里云参考文档链接地址: https://help.aliyun.com/document_detail/50452.html?spm=a2c4g.11186623.6.1355. ...
- UNITY2018 真机开启deepprofiling的操作
手机上运行游戏并开启deepprofiling的命令如下 命令一:adb shell am start -n com.szyh.YHP1.kaopu/com.szyh.YHP1.kaopu.MainA ...
- linux mce的一些相关内容和用户态监控的设计方法
之所以想起写一点关于mce的东西,倒不是因为遇到mce的异常了,之前遇到过很多mce的异常,内存居多,但没有好好记录下来,写这个是因为参加2018 clk南京会议的一点想法. void __init ...
- Oracle分区表常见操作
Oracle分区表常用于业务中大表使用,如历史交易记录表等,提高表记录查询效率.本文主要描述范围分区表的创建.新增以及索引创建. Oracle操作分区表相关信息 显示数据库所有分区表的信息:DBA_P ...
- 高效Java敏感词、关键词过滤工具包_过滤非法词句
敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的.前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢.我把它程序拿过来 ...
- 4.Java的流程控制.md
目录 1. break语句 2.continue 3.foreach语句 4.可变参数: 1. break语句 Java的break语句,正常情况下,break和c++一样,但是Java可以设置一个标 ...
- 把Swift中的String转成NSString ,获取NSString的方法
1.0 在Swift中的 String 并没有提供什么方法,直接把它自身转变成 Int .Float 等,而在OC中我们就可以这样 "123".integerValue 来获取它 ...
- hibernate 工作原理及为什么要用
- C# 监测每个方法的执行次数和占用时间(测试1)
在Nuget引用 Castle.DynamicProxy 和 Newtonsoft.Json 这个 原文:http://www.cnblogs.com/RicCC/archive/2010/03/15 ...