이 문서는 pcntl 확장 프로그램을 통해 수행된 다중 프로세스 테스트를 기반으로 합니다.
프로세스 스케줄링 전략
운영 체제는 상위 프로세스와 하위 프로세스의 스케줄링을 담당합니다. 먼저 하위 프로세스를 스케줄링할지 아니면 상위 프로세스를 스케줄링할지 여부는 시스템의 스케줄링 알고리즘에 따라 결정됩니다. 물론 지연을 추가할 수도 있습니다. 상위 프로세스에 연결하거나 프로세스 재활용 함수 pcntl_wait를 호출하면 하위 프로세스가 먼저 실행되도록 할 수 있습니다. 프로세스 재활용의 목적은 프로세스가 생성될 때 점유한 메모리 공간을 해제하여 좀비 프로세스가 되는 것을 방지하는 것입니다.
신호:
신호는 소프트 인터럽트 시스템 또는 소프트 인터럽트라고 하며, 그 기능은 프로세스에 비동기 이벤트 알림을 보내는 것입니다.
신호 번호: [소스 코드는 SIGINT, SIGTERM, SIGUSR1 신호를 기반으로 합니다. 의미는 kill 명령 매뉴얼을 확인하십시오. 설명은 제공되지 않습니다.]
linux는 64를 지원하며 그 중 절반은 실시간 신호입니다. 그 중 절반은 비실시간 신호입니다. 이러한 신호는 각각 고유한 숫자와 해당 정수 값을 갖습니다. 각 신호 번호의 의미는 관련 Linux 설명서 [man manual to find out]를 참조할 수 있습니다.
신호 처리 기능:
신호는 일반적으로 해당 기능에 바인딩되며 일부 신호에는 다음과 같은 기본 동작이 있습니다. SIGKILL, SIGTERM, SIGINT 작업 기본 작업은 프로세스를 종료하는 것입니다. 물론 pcntl_signal을 사용하여 덮어쓸 수도 있습니다.
신호의 개념: 하드웨어 인터럽트와 동일합니다. 이전 기사를 참조하거나 칩 하드웨어 인터럽트 원리를 확인하세요.
신호 전송:
kill 신호 번호 프로세스 또는 주요 제품의 인터럽트 신호를 사용하거나 소스 코드에서 posix_kill 및 기타 기능을 사용할 수 있습니다.
프로세스는 서로 격리되어 있으며 자체 스택 공간을 갖고 있으며, 일부 공통 텍스트[코드 영역] 외에도 자체 실행 코드도 있습니다. 프로세스가 실행될 때 CPU 리소스를 차지하며 다른 프로세스는 이를 차지합니다. 이때 다른 프로세스는 [앞서 언급한 tcp 서비스 등] 차단된 상태가 됩니다. 프로세스 기능을 종료하기 위해 종료하거나 신호 이벤트가 발생하면 종료됩니다.] 권한을 포기하고 메모리를 해제하면 다른 프로세스가 실행될 기회를 갖게 됩니다.
프로세스에는 자체 프로세스 설명자가 있으며, 그 중 프로세스 번호 PID가 더 일반적으로 사용됩니다. 프로세스가 실행 중일 때 해당 프로세스 파일이 시스템 /proc/PID에 생성되며 사용자가 직접 볼 수 있습니다. .
각 프로세스에는 자체 프로세스 그룹(프로세스 집합)이 있습니다. 여러 프로세스 그룹의 집합이 세션입니다. 세션 생성은 프로세스를 통해 생성되며 이 프로세스는 그룹 리더 프로세스가 될 수 없습니다. 세션 중 첫 번째 프로세스도 프로세스 그룹의 프로세스 리더가 되어 제어 터미널에서 분리됩니다. 이전 프로세스가 제어 터미널에 바인딩되어 있어도 [데몬 프로세스 생성]에서도 분리됩니다.
파일 설명 권한 마스크 [권한 마스크 단어]:
umask () Linux에서 이 명령을 실행한 다음 파일을 만들고 권한을 확인할 수 있습니다. [실행 후 아무것도 찾지 못하면 아직 충분하지 않음을 의미합니다. training^_^】
<?php /** * Created by PhpStorm. * User: 1655664358@qq.com * Date: 2018/3/26 * Time: 14:19 */ namespace Chen\Worker; class Server { public $workerPids = []; public $workerJob = []; public $master_pid_file = "master_pid"; public $state_file = "state_file.txt"; function run() { $this->daemon(); $this->worker(); $this->setMasterPid(); $this->installSignal(); $this->showState(); $this->wait(); } function wait() { while (1){ pcntl_signal_dispatch(); $pid = pcntl_wait($status); if ($pid>0){ unset($this->workerPids[$pid]); }else{ if (count($this->workerPids)==0){ exit(); } } usleep(100000); } } function showState() { $state = "\nMaster 信息\n"; $state.=str_pad("master pid",25); $state.=str_pad("worker num",25); $state.=str_pad("job pid list",10)."\n"; $state.=str_pad($this->getMasterPid(),25); $state.=str_pad(count($this->workerPids),25); $state.=str_pad(implode(",",array_keys($this->workerPids)),10); echo $state.PHP_EOL; } function getMasterPid() { if (file_exists($this->master_pid_file)){ return file_get_contents($this->master_pid_file); }else{ exit("服务未运行\n"); } } function setMasterPid() { $fp = fopen($this->master_pid_file,"w"); @fwrite($fp,posix_getpid()); @fclose($fp); } function daemon() { $pid = pcntl_fork(); if ($pid<0){ exit("fork进程失败\n"); }else if ($pid >0){ exit(0); }else{ umask(0); $sid = posix_setsid(); if ($sid<0){ exit("创建会话失败\n"); } $pid = pcntl_fork(); if ($pid<0){ exit("进程创建失败\n"); }else if ($pid >0){ exit(0); } //可以关闭标准输入输出错误文件描述符【守护进程不需要】 } } function worker() { if (count($this->workerJob)==0)exit("没有工作任务\n"); foreach($this->workerJob as $job){ $pid = pcntl_fork(); if ($pid<0){ exit("工作进程创建失败\n"); }else if ($pid==0){ /***************子进程工作范围**********************/ //给子进程安装信号处理程序 $this->workerInstallSignal(); $start_time = time(); while (1){ pcntl_signal_dispatch(); if ((time()-$start_time)>=$job->job_run_time){ break; } $job->run(posix_getpid()); } exit(0);//子进程运行完成后退出 /***************子进程工作范围**********************/ }else{ $this->workerPids[$pid] = $job; } } } function workerInstallSignal() { pcntl_signal(SIGUSR1,[__CLASS__,'workerHandleSignal'],false); } function workerHandleSignal($signal) { switch ($signal){ case SIGUSR1: $state = "worker pid=".posix_getpid()."接受了父进程发来的自定义信号\n"; file_put_contents($this->state_file,$state,FILE_APPEND); break; } } function installSignal() { pcntl_signal(SIGINT,[__CLASS__,'handleMasterSignal'],false); pcntl_signal(SIGTERM,[__CLASS__,'handleMasterSignal'],false); pcntl_signal(SIGUSR1,[__CLASS__,'handleMasterSignal'],false); } function handleMasterSignal($signal) { switch ($signal){ case SIGINT: //主进程接受到中断信号ctrl+c foreach ($this->workerPids as $pid=>$worker){ posix_kill($pid,SIGINT);//向所有的子进程发出 } exit("服务平滑停止\n"); break; case SIGTERM://ctrl+z foreach ($this->workerPids as $pid=>$worker){ posix_kill($pid,SIGKILL);//向所有的子进程发出 } exit("服务停止\n"); break; case SIGUSR1://用户自定义信号 if (file_exists($this->state_file)){ unlink($this->state_file); } foreach ($this->workerPids as $pid=>$worker){ posix_kill($pid,SIGUSR1); } $state = "master pid\n".$this->getMasterPid()."\n"; while(!file_exists($this->state_file)){ sleep(1); } $state.= file_get_contents($this->state_file); echo $state.PHP_EOL; break; } } } <?php /**\ * Created by PhpStorm.\ * User: 1655664358@qq.com * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker; class Job { public $job_run_time = 3600; function run($pid) {\sleep(3); echo "worker pid = $pid job 没事干,就在这里job\n"; } } <?php /** * Created by PhpStorm.\ * User: 1655664358@qq.com * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker; class Talk { public $job_run_time = 3600; function run($pid) {\sleep(3); echo "worker pid = $pid job 没事干,就在这里talk\n"; } } <?php /** * Created by PhpStorm.\ * User: 1655664358@qq.com * Date: 2018/3/26\ * Time: 15:45\ */ require_once 'vendor/autoload.php'; $process = new \Chen\Worker\Server(); $process->workerJob = [new \Chen\Worker\Talk(),new \Chen\Worker\Job()]; $process->run();
더 많은 Laravel 관련 기술 기사를 보려면 Laravel Framework Getting Started Tutorial 칼럼을 방문하여 알아보세요!
위 내용은 PHP 다중 프로세스 및 신호 인터럽트로 다중 작업 상주 메모리 관리 실현 [마스터/작업자 모델]의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!