美文网首页
php进程认识

php进程认识

作者: ysp123 | 来源:发表于2019-05-09 20:57 被阅读0次

    1、基本认识
    php系统提供了pcntl_fork 函数来操作进程。
    pcntl_fork:当前进程位置产生分支(子进程)。fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号,而子进程得到的是0。

    $pid = pcntl_fork();   //创建子进程
    if($pid < 0){
          echo "子进程创建失败".PHP_EOL;
    }elseif($pid){
          echo "子进程pid --   ".$pid.PHP_EOL;
    }else{
           echo "执行子进程 ---".posix_getpid().PHP_EOL;
    }
    

    2、孤儿进程
    孤儿进程:一个父进程退出,而它的子进程或多个子进程还在运行,那么那些子进程将成为孤儿进程,孤儿进程将被init进程(进程号为1)收养,并由init进程对他们完成状态收集。
    孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

    $pid = pcntl_fork();   //创建子进程
    if($pid < 0){
          echo "子进程创建失败".PHP_EOL;
    }elseif($pid){
          echo "子进程pid --   ".$pid.PHP_EOL;
    }else{
           sleep(30); 
           echo "执行子进程 ---".posix_getpid().PHP_EOL;
    }
    

    3、僵尸进程
    僵尸进程:一个进程使用fork创建子进程,如果子进程退出,父进程没有调用wait或 waitpid获取子进程的状态信息,那么子进程的描述符任然保存在系统中。这种进程称为僵尸进程。
    任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
    对于linux系统来说,一个长时间运行的多进程程序一定要回收子进程,因为系统的进程资源是有限的,僵尸进程会让系统的可用资源减少。

    $pid = pcntl_fork();   //创建子进程
    if($pid < 0){
          echo "子进程创建失败".PHP_EOL;
    }elseif($pid){
          sleep(30);   //主进程被挂起,30秒内为退出
          echo "子进程pid --   ".$pid.PHP_EOL;
    }else{
           echo "执行子进程 ---".posix_getpid().PHP_EOL;
    }
    

    上边我们已经说了僵尸进程的危害,那么如何避免僵尸进程。使用

    pcntl_wait($status);  //该函数阻塞当前进程,只到当前进程的一个子进程退出或者收到一个结束当前进程的信号
     pcntl_waitpid($pid, $status);  //pcntl_waitpid()和pcntl_wait()功能相同。前者第一个参数支持指定pid参数,当指定-1作为pid的值等同于后者。
    
    $pid = pcntl_fork();   //创建子进程
    if($pid < 0){
          echo "子进程创建失败".PHP_EOL;
    }elseif($pid){
          pcntl_wait($status);  或  pcntl_waitpid($pid, $status);
          sleep(30);   //主进程被挂起,30秒内为退出
          echo "子进程pid --   ".$pid.PHP_EOL;
    }else{
           echo "执行子进程 ---".posix_getpid().PHP_EOL;
    }
    

    以上是单进程进程回收,下边我们看下多进程的进程回收,阻塞的回收方式和以上一样,下边我们使用非阻塞

    pcntl_wait($status, WNOHANG);
     pcntl_waitpid($pid, $status, WNOHANG);  
    
    $child_pids = [];
    
    for($i=0;$i<3;$i++){
        $pid = pcntl_fork();
        if($pid<0){
            exit('进程创建失败!!');
        }elseif($pid){
              //$res = pcntl_wait($status, WNOHANG);
              //$res =  pcntl_waitpid($pid, $status, WNOHANG);
              echo "父进程pid --". posix_getppid()."  子进程pid  ".$pid;
        }else{
            echo "执行子进程".posix_getpid();
            exit();   //子进程需要exit,防止子进程也进入for循环。如果没有exit(),最终创建的子进程不只3个。
        }
    }
    
    while(count($child_pids)){
          foreach($child_pids as $key => $pid){
                //$res = pcntl_wait($status, WNOHANG);
                $res =  pcntl_waitpid($pid, $status, WNOHANG);
                //var_dump($res);
                //exit();
                if ($res == -1 || $res > 0){
                        echo time()." Child process exit,pid {$pid}\n";   
                       unset($child_pids[$key]);
                 }else{
                      echo time()." Wait End,pid {$pid}\n";   
                 }
          }
    }
    

    以上及实现了进程的非阻塞(备足:若结果不明显则加大进程数)

    学习编程就是升级打怪的过程。从最开始的静态页面到动态页面,从基本的curd到业务架构,数据存储到大数据处理,从基本的http请求到网络处理,每一次技能的上升都是一次打怪升级。

    相关文章

      网友评论

          本文标题:php进程认识

          本文链接:https://www.haomeiwen.com/subject/inmgoqtx.html