php多进程编程二

php在pcntl_ fork()后生成的 子进程(通常为僵尸进 程)必须由pcntl _waitpid() 函数进行资源释放。但 在pcntl_wait pid()不一定释放 的就是当前运行的进程 ,也可能是过去生成的 僵尸进程(没有释放) ;也可能是并发时其它 访问者的僵尸进程。但 可以 使用posix_ki ll($cid, SIGTERM)在子 进程结束时杀掉它。
子进程会自动复制父进 程空间里的变量。
PHP多进程编程示例2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
//.....
//需要安装pcntl的php扩展,并加载它
if(function_exists("pcntl_fork")){
   //生成子进程
  $pid = pcntl_fork();
  if($pid == -1){
    die('could not fork');
  }else{
    if($pid){
      $status = 0;
      //阻塞父进程,直到子进程结束,不适合需要长时间运行的脚本,可使用pcntl_wait($status, 0)实现非阻塞式
      pcntl_wait($status);
      // parent proc code
      exit;
    }else{
      // child proc code
      //结束当前子进程,以防止生成僵尸进程
      if(function_exists("posix_kill")){
        posix_kill(getmypid(), SIGTERM);
      }else{
        system('kill -9'. getmypid());
      }
      exit;
    }
  }
}else{
   // 不支持多进程处理时的代码在这里
}
//.....
?>

如果不需要阻塞进程, 而又想得到子进程的退 出状态,则可以注释掉 pcntl_wait ($status)语 句,或写成:
<?php
pcntl_wait($status, 1);
//或
pcntl_wait($status, WNOHANG);

在上面的代码中,如果父进程退出(使用exit函数退出或redirect),则会导致子进程成为僵尸进程(会交给init进程控制),子进程不再执行。
僵 尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程.(zombie)进程。任何进程在退出前(使用exit退出)都会变成 僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多, 最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。
预防僵尸进程有以下几种方法:
  • 父 进程通过wait和waitpid等函数使其等待子进程结束,然后再执行父进程中的代码,这会导致父进程挂起。上面的代码就是使用这种方式实现的,但在WEB环境下,它不适合子进程需要长时间运行的情况(会导致超时)。使用wait和waitpid方法使父进程自动回收其僵尸子进程(根据子进程的返回状 态),waitpid用于临控指定子进程,wait是对于所有子进程而言。
  • 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收
  • 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号,例如:pcntl_signal(SIGCHLD, SIG_IGN);
    $pid = pcntl_fork();
    //....code

  • 还有一个技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程再fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。下面是一个例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include "apue.h"
    #include

    int main(void){
      pid_t    pid;

      if ((pid = fork()) < 0){
         err_sys("fork error");
      } else if (pid == 0){     /**//* first child */
        if ((pid = fork()) < 0){
           err_sys("fork error");
        }elseif(pid > 0){
           exit(0);    /**//* parent from second fork == first child */
        }

        /**
         * We're the second child; our parent becomes init as soon
         * as our real parent calls exit() in the statement above.
         * Here's where we'd continue executing, knowing that when
         * we're done, init will reap our status.
         */

         sleep(2);
         printf("second child, parent pid = %d ", getppid());
         exit(0);
      }

      if (waitpid(pid, NULL, 0) != pid)  /**//* wait for first child */
        err_sys("waitpid error");

      /**
       * We're the parent (the original process); we continue executing,
       * knowing that we're not the parent of the second child.
       */

       exit(0);
    }

    在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill-9也不能杀死僵尸进 程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为”孤儿进程”,过继给1号进程init,init会定期调用wait回收 清理这些父进程已退出的僵尸子进程。
    所以,上面的示例可以改成:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <?php

//.....
//需要安装pcntl的php扩展,并加载它
if(function_exists("pcntl_fork")){
   //生成第一个子进程
  $pid = pcntl_fork();  //$pid即所产生的子进程id
  if($pid == -1){
    //子进程fork失
    die('could not fork');
  }else{
    if($pid){
      //父进程code
      sleep(5);  //等待5秒
      exit(0); //或$this->_redirect('/');
    }else{
      //第一个子进程code
      //产生孙进程
      if(($gpid = pcntl_fork()) < 0){ $gpid即所产生的孙进程id
        //孙进程产生失败
        die('could not fork');
      }elseif($gpid > 0){
        //第一个子进程code,即孙进程的父进
        $status = 0;
        $status = pcntl_wait($status); //阻塞子进程,并返回孙进程的退出状态,用于检查是否正常退出
        if($status ! = 0) file_put_content('filename', '孙进程异常退出');
        //得到父进程id
        //$ppid =  posix_getppid(); //如果$ppid为1则表示其父进程已变为init进程,原父进程已退出
        //得到子进程id:posix_getpid()或getmypid()或是fork返回的变量$pid
        //kill掉子进程
        //posix_kill(getmypid(), SIGTERM);
        exit(0);
      }else{ //即$gpid == 0
        //孙进程code
        //....
        //结束孙进程(即当前进程),以防止生成僵尸进程
        if(function_exists('posix_kill')){
           posix_kill(getmypid(), SIGTERM);
        }else{
           system('kill -9'. getmypid());
        }
        exit(0);
      }
    }
  }
}else{
   // 不支持多进程处理时的代码在这里
}
//.....
?>
怎样产生僵尸进程的

一 个进程在调用exit 命令结束自己的生命的 时候,其实它并没有真 正的被销毁,而是留下 一个称为僵尸进程(Z ombie)的数据结 构(系统调用exit ,它 的作用是使进程退出, 但也仅仅限于将一个正 常的进程变成一个僵尸 进程,并不能将其完全 销毁)。在Linux 进程的状态中,僵尸进 程是非常特殊的一种, 它已 经放弃了几乎所有内存 空间,没有任何可执行 代码,也不能被调度, 仅仅在进程列表中保留 一个位置,记载该进程 的退出状态等信息供其 他进程收集,除此之外 ,僵 尸进程不再占有任何内 存空间。它需要它的父 进程来为它收尸,如果 他的父进程没安装SI GCHLD信号处理函 数调用wait或wa itpid()等待子 进程 结束,又没有显式忽略 该信号,那么它就一直 保持僵尸状态,如果这 时父进程结束了,那么 init进程自动会接 手这个子进程,为它收 尸,它还是能被清除的 。但 是如果如果父进程是一 个循环,不会结束,那 么子进程就会一直保持 僵尸状态,这就是为什 么系统中有时会有很多 的僵尸进程。
任何一个子进程(in it除外)在exit() 之后,并非马上就消失 掉,而是留下一个称为 僵尸进程(Zombi e)的数据结构,等待 父进程处理。这是每个 子进程在结束时都要经 过的 阶段。如果子进程在e xit()之后,父进 程没有来得及处理,这 时用ps命令就能看到 子进程的状态是”Z” 。如果父进程能及时  处理,可能用ps命令 就来不及看到子进程的 僵尸状态,但这并不等 于子进程不经过僵尸状 态。
如果父进程在子进程结 束之前退出,则子进程 将由init接管。i nit将会以父进程的 身份对僵尸状态的子进 程进行处理。
另外,还可以写一个p hp文件,然后在以后 台形式来运行它,例如
<?php
  //Action代码
  public function createAction(){
    //....
    //将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
    system('php -f insertLargeData.php ' . ' args ' . '&');
    $this->redirect('/');
  }
?>

然后在insertLargeData.php文件中做数据库操作。也可以用cronjob + php的方式实现大数据量的处理。
如果是在终端运行php命令,当终端关闭后,刚刚执行的命令也会被强制关闭,如果你想让其不受终端关闭的影响,可以使用nohup命令实现:
<?php
  //Action代码
  public function createAction(){
    //....
    //将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
    system('nohup php -f insertLargeData.php ' . ' args ' . '&');
    $this->redirect('/');
  }
?>
以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值