铁雪资源网 Design By www.gsvan.com

    PHP有一组进程控制函数(编译时需要–enable-pcntl与posix扩展),使得php能实现跟c一样的创建子进程、使用exec函数执行程序、处理信号等功能。
   

<"pcntl_fork")) { 
    die("pcntl extention is must !"); 
  } 
  //总进程的数量 
  $totals = 3; 
  // 执行的脚本数量 
  $cmdArr = array(); 
  // 执行的脚本数量的数组 
  for ($i = 0; $i < $totals; $i++) { 
    $cmdArr[] = array("path" => __DIR__ . "/run.php", 'pid' =>$i ,'total' =>$totals); 
  } 
   
  /* 
  展开:$cmdArr 
  Array 
  ( 
    [0] => Array 
      ( 
        [path] => /var/www/html/company/pcntl/run.php 
        [pid] => 0 
        [total] => 3 
      ) 
   
    [1] => Array 
      ( 
        [path] => /var/www/html/company/pcntl/run.php 
        [pid] => 1 
        [total] => 3 
      ) 
   
    [2] => Array 
      ( 
        [path] => /var/www/html/company/pcntl/run.php 
        [pid] => 2 
        [total] => 3 
      ) 
   
  ) 
  */ 
   
  pcntl_signal(SIGCHLD, SIG_IGN); //如果父进程不关心子进程什么时候结束,子进程结束后,内核会回收。 
  foreach ($cmdArr as  $cmd) { 
    $pid = pcntl_fork();  //创建子进程 
    //父进程和子进程都会执行下面代码 
    if ($pid == -1) { 
      //错误处理:创建子进程失败时返回-1. 
      die('could not fork'); 
    } else if ($pid) { 
      //父进程会得到子进程号,所以这里是父进程执行的逻辑 
      //如果不需要阻塞进程,而又想得到子进程的退出状态,则可以注释掉pcntl_wait($status)语句,或写成: 
      pcntl_wait($status,WNOHANG); //等待子进程中断,防止子进程成为僵尸进程。 
    } else { 
      //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。 
      $path  = $cmd["path"]; 
      $pid = $cmd['pid'] ; 
      $total = $cmd['total'] ; 
      echo exec("/usr/bin/php {$path} {$pid} {$total}")."\n"; 
      exit(0) ; 
    } 
  } 
  "htmlcode">
<"Caught SIGALRM\n";
  pcntl_alarm(5);
}
 
pcntl_signal(SIGALRM, "signal_handler", true);
pcntl_alarm(5);
 
for(;;) {
}
 
"htmlcode">
<"htmlcode">
<"htmlcode">
<"parent process,pid {$id}, child pid {$pid}\n";
}else{
  $id = getmypid();
  echo "child process,pid {$id}\n";
  sleep(2);
}
"htmlcode">
<"Method '__fork' not found!");
  }
 
  if(is_array($arg)){
   $i=0;
   foreach($arg as $key=>$val){
    $spawns[$i]=$key;
    $i++;
    $this->spawn($obj,$key,$val);
   }
   $spawns['total']=$i;
  }elseif($spawns=intval($arg)){
   for($i = 0; $i < $spawns; $i++){
    $this->spawn($obj,$i);
   }
  }else{
   exit('Bad argument!');
  }
 
  if($i>1000) exit('Too many spawns!');
   return $this->request($spawns);
  }
 
 /**
  * Signfork主进程控制方法
  * 1、$tmpfile 判断子进程文件是否存在,存在则子进程执行完毕,并读取内容
  * 2、$data收集子进程运行结果及数据,并用于最终返回
  * 3、删除子进程文件
  * 4、轮询一次0.03秒,直到所有子进程执行完毕,清理子进程资源
  * @param string&#124;array $arg 用于对应每个子进程的ID
  * @return array 返回  array([子进程序列]=>[子进程执行结果]);
  */
  private function request($spawns){
   $data=array();
   $i=is_array($spawns)"htmlcode">
<"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{
  // 不支持多进程处理时的代码在这里
}
//.....
"htmlcode">
<"htmlcode">
#include "apue.h"
#include <sys/wait.h>
 
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回收清理这些父进程已退出的僵尸子进程。

所以,上面的示例可以改成:
 

<"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{
 // 不支持多进程处理时的代码在这里
}
//.....
"htmlcode">
<"htmlcode">
<?php
//Action代码
public function createAction(){
  //....
  //将args替换成要传给insertLargeData.php的参数,参数间用空格间隔
  system('nohup php -f insertLargeData.php ' . ' args ' . '&');
  $this->redirect('/');
}
?>

你还可以使用screen命令代替nohup命令。

标签:
PHP,多进程

铁雪资源网 Design By www.gsvan.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
铁雪资源网 Design By www.gsvan.com

评论“以实例全面讲解PHP中多进程编程的相关函数的使用”

暂无以实例全面讲解PHP中多进程编程的相关函数的使用的评论...

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?