php进程认识

2019-05-09  本文已影响0人  ysp123

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请求到网络处理,每一次技能的上升都是一次打怪升级。

上一篇下一篇

猜你喜欢

热点阅读