zoukankan      html  css  js  c++  java
  • php多进程

    认识僵尸进程

    1、如果父进程先退出

    子进程自动被 init 进程收养,不会产生僵尸进程
     
    2、如果子进程先退出 ,父进程一直不退出, 子进程会一直存在成为僵尸进程   (php为守护进程while(true)的时候,很容易出现僵尸进程)

    2.1 父进程 wait() 处理,则僵尸进程会被父进程清理

    2.2 如果父进程不用 wait() 处理,则僵尸进程会在父进程退出之前一直存在。当然,父进程退出后,僵尸子进程会被 init 收养,init 进程会自动调用 wait() 处理。但是对于处理网络请求的服务器进程来说,父进程可能会一直存在,子进程处理完任务就退出,这种情况下会产生很多僵尸进程,这种场景就需要对僵尸进程的处理提高警惕了。

    fork函数详解

    pcntl_fork() — 在当前进程当前位置产生分支(子进程)。此函数创建了一个新的子进程后,子进程会继承父进程当前的上下文,和父进程一样从pcntl_fork()函数处继续向下执行,只是获取到的pcntl_fork()的返回值不同,我们便能从判断返回值来区分父进程和子进程,分配父进程和子进程去做不同的逻辑处理。

    pcntl_fork()函数成功执行时会在父进程返回子进程的进程id(pid),因为系统的初始进程init进程的pid为1,后来产生进程的pid都会大于此进程,所以我们可以通过判断pcntl_fork()的返回值大于1来确实当前进程是父进程;

    而在子进程中,此函数的返回值会是固定值0,我们也可以通过判断pcntl_fork()的返回值为0来确定子进程;

    而pcntl_fork()函数在执行失败时,会在父进程返回-1,当然也不会有子进程产生。

    posix_getpid():获取当前进程的pid;

    cli_set_process_title('响亮的名字'):为当前进程取一个响亮的名字

    管理子进程

    创建好了进程,那么怎么对子进程进行管理呢?使用信号。

    在计算机科学中,信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。

    分发信号处理器

    我们通过在父进程接收子进程传来的信号,判断子进程状态,来对子进程进行管理。

    我们需要在父进程里使用pcntl_signal()函数和pcntl_signal_dispatch()函数来给各个子进程安装信号处理器。

    pcntl_signal (int $signo , callback $handler) 安装一个信号处理器;
            $signo是待处理的信号常量,callback是其处理函数
    
    pcntl_signal_dispatch () 调用每个等待信号通过pcntl_signal()安装的处理器

    PHP内常见的信号常量有:

            SIGCHLD     子进程退出成为僵尸进程会向父进程发送此信号
            SIGHUP      进程挂起
            SIGTEM      进程终止
            ...         // 其他请在手册中查看

    安装并调用信号处理器后,一旦子进程有相应的信号返回给父进程,父进程就可以调用相应的callback函数对子进程处理;

    处理子进程

    对子进程的处理方法有:

    posix_kill():此函数并不能顾名思义,它通过向子进程发送一个信号来操作子进程,在需要要时可以选择给子进程发送进程终止信号来终止子进程;

    pcntl_waitpid():等待或返回fork的子进程状态,如果指定的子进程在此函数调用时已经退出(俗称僵尸进程),此函数将立刻返回,并释放子进程的所有系统资源,此进程可以避免子进程变成僵尸进程,造成系统资源浪费;

    下面是两个函数的函数原型:

    bool posix_kill ( int $pid , int $sig ) // 向进程id为$pid的进程发送$sig信号,$sig常见信号如上;
    
    int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )  //挂起当前进程的执行直到进程号为$pid的进程退出(如果$pid为-1,则等待任意一个子进程); 

    示例代码
    <?php
    header('content-type:text/html;charset=utf-8' );   
    // 必须加载扩展  
    if (!function_exists("pcntl_fork")) {  
        die("pcntl extention is must !");  
    }else{
    	//echo "ok";	
    }
    $totals = 3;  
    // 执行的脚本数量    
    pcntl_signal(SIGCHLD, SIG_IGN); //忽略子进程返回信号,如果父进程不关心子进程什么时候结束,子进程结束后,内核会回收。
    for ($i = 0; $i < $totals; $i++) { 
    	$pid = pcntl_fork();
    	 if ($pid == -1) {  
            //错误处理:创建子进程失败时返回-1.  
            die('could not fork');  
        } else if ($pid) {  
    		echo "pid:".$pid."
    ";
            //父进程会得到子进程号,所以这里是父进程执行的逻辑
    		// pcntl_wait($status); // 父进程必须等待一个子进程退出后,再创建下一个子进程。
    		//   pcntl_wait($status,WNOHANG); 不等待子进程退出,直接创建下一个
            //如果不需要阻塞进程,而又想得到子进程的退出状态,则可以注释掉pcntl_wait($status)语句,或写成:  
            pcntl_wait($status,WNOHANG); //等待子进程中断,防止子进程成为僵尸进程。
    		echo  "status:".$status."
    ";
        } else {  
    		$cpid = posix_getpid();//获取当前进程的pid;
            echo $cpid."
    ";
    		
    		//cli_set_process_title("我是{$ppid}的子进程,我的进程id是{$cpid}.");  为当前进程取一个响亮的名字
    		
    		//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。   
            echo exec("/usr/bin/php -f /home/wwwroot/seo/test/sub.php ".$i." &")."
    ";  
            exit(0) ;  
        }
    	sleep(1);
    }
    

      

     
  • 相关阅读:
    h5页面页面在iphoneX手机上底部会有留白解决办法
    自定义单张图片放大预览功能,可支持手势缩放,依赖jquery
    js事件内部有click事件时,click事件会重复调用解决方法
    h5页面通过阿里云的broswer-js-sdk上传文件
    python字符串前加r、f、u、l 的区别
    Python基础面试题 :计算列表中出现最多次的字符
    python基础入门教程:传参是传值还是传引用
    Python 面试题:输入一个数组,输出该数组的第二大的数字
    Python 7种超实用的数据清洗方法,这你一定要掌握
    python教程:3个非常有用的内置函数(filter/map/reduce)
  • 原文地址:https://www.cnblogs.com/microtiger/p/7677674.html
Copyright © 2011-2022 走看看