当前位置:首页 > PHP教程 > php高级应用 > 列表

浅谈PHP进程管理

发布:smiling 来源: PHP粉丝网  添加日期:2021-11-12 10:04:45 浏览: 评论:0 

这篇文章主要介绍了PHP进程管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

这篇文章是对之前一篇文章的补充和改进, 创建一个主(master)进程,主进程安装定时器,每隔5分钟检测一次队列长度,根据队列长度计算需要的worker进程,然后创建或者杀掉子进程。这样做的好处是防止队列堆积,任务得不到及时处理。更新业务代码,只需要reload操作即可。

整个流程有以下知识点:

创建守护进程的步骤:

设置默认文件权限

fork一个进程,父进程退出

调用setsid创建一个新的会话

将当前工作目录更改为根目录

关闭不再需要的文件描述符

使用信号实现定时器

上一篇定时器依赖于系统的定时任务,这次使用闹钟信号实现,php 5.3.0以下的版本依赖于ticks,5.3.0及以上版本可使用pcntl_signal_dispatch

信号:提供了一种异步事件处理的方法,在某个信号出现时,进程有以下三种方式对信号进行处理

忽略此信号

捕捉信号

执行系统默认动作,大多数信号的默认动作是终止该进程

常见信号

SIGKILL,SIGSTOP是两种不能被用户忽略和捕捉的信号

SIGINT(2):程序终止信号,通常是Ctrl-C)时发出,用于通知前台进程组终止进程

SIGQUIT(3):和SIGINT类似, 但由QUIT字符(通常是Ctrl+/)来控制. 进程收到该消息退出时会产生core文件

SIGKILL(9):立即终止进程,不可被忽略捕捉或阻塞

SIGUSR1(10):用户定义信号

SIGUSR2(12):留给用户使用

SIGALRM(14):闹钟信号

SIGTERM(15):终止进程,可被程序捕捉,使得进程可以执行完清理操作。

SIGSTOP(19):停止一个进程,该进程还未结束, 只是暂停执行

防止产生僵尸进程

所有的进程在退出的时候都会成为僵尸进程,这时候如果父进程还在运行,没有调用wait或者waitpid,则僵尸进程占用的资源不会被清理,如果父进程已终止,僵尸进程由init进程进行清理。

抽调业务代码,主要代码如下

其中要注意的一点,创建守护进程关闭输入输出,错误输出流的时候,如果代码后面有echo等输出字符,将出现致命错误,需要在php代码中重定向输出流到/dev/null。或者在终端启动进程的时候进行重定向

  1. <?php 
  2. define('PROC_MAX', 10); 
  3. define('PROC_MIN', 5); 
  4.    
  5. $cmd = $argv[1]; 
  6. $aPid = []; 
  7. $pidFile = __DIR__ . '/pid.pid'
  8. $pid = file_get_contents($pidFile); 
  9.    
  10. switch($cmd){ 
  11.  case 'start' : 
  12.   if(posix_kill($pid, 0)){ 
  13.    echo "gamelog process is already exsits!\n"
  14.    return false; 
  15.   } 
  16.   //设置默认文件权限 
  17.   umask(022); 
  18.   //fork 
  19.   $pid = pcntl_fork(); 
  20.   if($pid < 0){ 
  21.    exit('fork error!'); 
  22.   }else if($pid > 0){ 
  23.    exit
  24.   } 
  25.   //脱离当前终端 
  26.   posix_setsid(); 
  27.   //将当前工作目录更改为根目录 
  28.   chdir('/'); 
  29.   //关闭文件描述符 
  30.   fclose(STDIN); 
  31.   fclose(STDOUT); 
  32.   fclose(STDERR); 
  33.   //重定向输入输出 
  34.   global $STDOUT$STDERR
  35.   $STDOUT = fopen('/dev/null''a'); 
  36.   $STDERR = fopen('/dev/null''a'); 
  37.      
  38.   cli_set_process_title('gamelog:master'); 
  39.   $pid = posix_getpid(); 
  40.   file_put_contents($pidFile$pid); 
  41.   //闹钟信号 
  42.   pcntl_signal(SIGALRM, function() use (&$aPid) { 
  43.    pcntl_alarm(300); 
  44.    $workerNum = mt_rand(1, 20);//此处检测你需要的进程数 
  45.    $daemonNum = count($aPid); 
  46.       
  47.    ($workerNum > PROC_MAX) && ($workerNum = PROC_MAX); 
  48.    if($daemonNum < $workerNum){ 
  49.     $procNum = $workerNum - $daemonNum
  50.     $procNum = max(PROC_MIN, $procNum); 
  51.     for($p = 1; $p <= $procNum$p++){ 
  52.      $pid = pcntl_fork(); 
  53.      if ($pid < 0) { 
  54.       exit('fork error!'); 
  55.      } else if ($pid == 0) { 
  56.       cli_set_process_title('gamelog:worker'); 
  57.       while (true) { 
  58.        //do your work 
  59.        usleep(100); 
  60.       } 
  61.       exit(); 
  62.      } else { 
  63.       $aPid[] = $pid
  64.      } 
  65.     } 
  66.    }else if($daemonNum > $workerNum){ 
  67.     $wokerNum = max($wokerNum, PROC_MIN); 
  68.     $killNum = $daemonNum - $workerNum
  69.     foreach($aPid as $key=>$pid){ 
  70.      if(posix_kill($pid, SIGKILL)){ 
  71.       unset($aPid[$key]); 
  72.       if(--$killNum <= 0){ 
  73.        break
  74.       } 
  75.      } 
  76.     } 
  77.    } 
  78.   }, false); 
  79.      
  80.   pcntl_signal(SIGUSR1, function() use (&$aPid$pid){ 
  81.    foreach($aPid as $key=>$chpid){ 
  82.     if(!posix_kill($chpid, SIGKILL)){ 
  83.      echo "kill child $chpid faild\n"
  84.     } 
  85.    } 
  86.    posix_kill($pid, SIGKILL); 
  87.   }, false); 
  88.      
  89.   pcntl_signal(SIGUSR2, function() use (&$aPid$pid){ 
  90.    foreach($aPid as $key=>$chpid){ 
  91.     if(!posix_kill($chpid, SIGKILL)){ 
  92.      echo "kill child $chpid faild\n"
  93.     } 
  94.    } 
  95.    if(!posix_kill($pid, SIGALRM)){ 
  96.     echo "restart gamelog faild\n"
  97.    } 
  98.   }, false); 
  99.      
  100.   posix_kill($pid, SIGALRM); 
  101.   while (true) { 
  102.    pcntl_signal_dispatch(); 
  103.    $pid = pcntl_wait($status, WUNTRACED);//不阻塞 
  104.   } 
  105.   break
  106.     
  107.  case 'stop' : 
  108.   if(!posix_kill($pid, SIGUSR1)){ 
  109.    exit('stop gamelog process error!'); 
  110.   } 
  111.   break
  112.  case 'reload' : 
  113.   if(!posix_kill($pid, SIGUSR2)){ 
  114.    exit('restop gamelog process error!'); 
  115.   } 
  116.   break
  117.  default : 
  118.   echo "Useage php signal.php start|stop|reload\n"
  119. }

Tags: PHP进程管理

分享到: