이 기사는 PHP 프로세스 관리에 대한 코드 예제를 제공합니다. 필요한 친구들이 참고할 수 있기를 바랍니다.
이 글은 이전 글을 보완하고 개선한 글입니다. 마스터 프로세스에 타이머를 설치하고, 5분마다 큐 길이를 감지하고, 큐 길이에 따라 필요한 작업자 프로세스를 계산합니다.
그런 다음 하위 프로세스를 생성하거나 종료합니다. 이것의 장점은 대기열이 쌓이고 작업이 제 시간에 처리되지 않는 것을 방지할 수 있다는 것입니다. 비즈니스 코드를 업데이트하려면 다시 로드 작업만 필요합니다.
전체 프로세스에는 다음 지식 포인트가 있습니다.
데몬 프로세스를 만드는 단계:
기본 파일 권한 설정
프로세스를 포크하면 상위 프로세스가 종료됩니다
setid 호출 새 세션 생성
현재 작업 디렉터리를 루트 디렉터리로 변경
더 이상 필요하지 않은 파일 설명자를 닫습니다.
신호를 사용하여 타이머 구현
이전 기사 타이머는 시스템에 의존합니다. timing 이 작업은 알람 시계 신호를 사용하여 구현됩니다. PHP 5.3.0 이하 버전은 틱을 사용합니다. 버전 5.3.0 이상에서는 pcntl_signal_dispatch
Signal을 사용할 수 있습니다. 특정 신호가 발생하면 프로세스가 수행됩니다. 신호를 처리하는 세 가지 방법이 있습니다.
이 신호를 무시합니다.
신호를 캡처합니다.
시스템 기본 작업을 수행합니다. 대부분의 신호에 대한 기본 작업은 프로세스를 종료하는 것입니다.
공통 신호
SIGKILL 및 SIGSTOP은 사용자가 무시하고 캡처할 수 없는 두 가지 신호입니다
SIGINT(2): 프로그램 종료 신호(일반적으로 Ctrl-C), 프로세스를 종료하도록 포그라운드 프로세스 그룹에 알리는 데 사용됩니다.
SIGQUIT( 3): SIGINT와 유사하지만 QUIT 문자(일반적으로 Ctrl+/)에 의해 제어됩니다. 프로세스가 이 메시지를 받고 종료되면 코어 파일이 생성됩니다.
SIGKILL(9): 프로세스를 즉시 종료하고 무시하거나 차단할 수 없습니다
SIGUSR1(10): 사용자 정의 신호
SIGUSR2(12): 사용자에게 맡김
SIGALRM(14): 알람 신호
SIGTERM(15): 프로세스를 종료하고 캡처할 수 있습니다. 프로세스가 정리 작업을 완료할 수 있도록 프로그램에 의해 수행됩니다.
SIGSTOP(19): 프로세스가 아직 종료되지 않았습니다.
모든 프로세스가 종료되면 좀비 프로세스가 됩니다. 부모 프로세스가 여전히 실행 중인 경우 wait 또는 waitpid가 호출되지 않으면 좀비 프로세스가 차지하는 리소스는 정리되지 않습니다. 부모 프로세스가 종료되면 좀비 프로세스는 init 프로세스에 의해 정리됩니다. .
한 가지 주의할 점은 입력 및 출력을 닫는 데몬 프로세스를 생성할 때 오류 출력 스트림 뒤에 에코 및 기타 출력 문자가 있는 경우입니다. 코드를 실행하면 출력 스트림을 /dev/null로 리디렉션하기 위해 PHP 코드에 있어야 하는 치명적인 오류가 발생합니다. 또는 터미널이 프로세스를 시작할 때 리디렉션
<?php
define('PROC_MAX', 10);
define('PROC_MIN', 5);
$cmd = $argv[1];
$aPid = [];
$pidFile = __DIR__ . '/pid.pid';
$pid = file_get_contents($pidFile);
switch($cmd){
case 'start' :
if(posix_kill($pid, 0)){
echo "gamelog process is already exsits!\n";
return false;
}
//设置默认文件权限
umask(022);
//fork
$pid = pcntl_fork();
if($pid < 0){
exit('fork error!');
}else if($pid > 0){
exit;
}
//脱离当前终端
posix_setsid();
//将当前工作目录更改为根目录
chdir('/');
//关闭文件描述符
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
//重定向输入输出
global $STDOUT, $STDERR;
$STDOUT = fopen('/dev/null', 'a');
$STDERR = fopen('/dev/null', 'a');
cli_set_process_title('gamelog:master');
$pid = posix_getpid();
file_put_contents($pidFile, $pid);
//闹钟信号
pcntl_signal(SIGALRM, function() use (&$aPid) {
pcntl_alarm(300);
$workerNum = mt_rand(1, 20);//此处检测你需要的进程数
$daemonNum = count($aPid);
($workerNum > PROC_MAX) && ($workerNum = PROC_MAX);
if($daemonNum < $workerNum){
$procNum = $workerNum - $daemonNum;
$procNum = max(PROC_MIN, $procNum);
for($p = 1; $p <= $procNum; $p++){
$pid = pcntl_fork();
if ($pid < 0) {
exit('fork error!');
} else if ($pid == 0) {
cli_set_process_title('gamelog:worker');
while (true) {
//do your work
usleep(100);
}
exit();
} else {
$aPid[] = $pid;
}
}
}else if($daemonNum > $workerNum){
$wokerNum = max($wokerNum, PROC_MIN);
$killNum = $daemonNum - $workerNum;
foreach($aPid as $key=>$pid){
if(posix_kill($pid, SIGKILL)){
unset($aPid[$key]);
if(--$killNum <= 0){
break;
}
}
}
}
}, false);
pcntl_signal(SIGUSR1, function() use (&$aPid, $pid){
foreach($aPid as $key=>$chpid){
if(!posix_kill($chpid, SIGKILL)){
echo "kill child $chpid faild\n";
}
}
posix_kill($pid, SIGKILL);
}, false);
pcntl_signal(SIGUSR2, function() use (&$aPid, $pid){
foreach($aPid as $key=>$chpid){
if(!posix_kill($chpid, SIGKILL)){
echo "kill child $chpid faild\n";
}
}
if(!posix_kill($pid, SIGALRM)){
echo "restart gamelog faild\n";
}
}, false);
posix_kill($pid, SIGALRM);
while (true) {
pcntl_signal_dispatch();
$pid = pcntl_wait($status, WUNTRACED);//不阻塞
}
break;
case 'stop' :
if(!posix_kill($pid, SIGUSR1)){
exit('stop gamelog process error!');
}
break;
case 'reload' :
if(!posix_kill($pid, SIGUSR2)){
exit('restop gamelog process error!');
}
break;
default :
echo "Useage php signal.php start|stop|reload\n";
}
위 내용은 PHP 프로세스 관리를 위한 코드 예제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!