높은 동시성 또는 배치 처리 시나리오에서는 종종 배경 작업이 CPU를 "먹고"외부 서비스에 대한 응답에 영향을 미치는 것을 원하지 않습니다. 운영 체제는 현재 프로세스 조정에 우선 순위를 제공했습니다. 아동 프로세스를 제어하려면 Fork Child 프로세스에서 호출하거나 Proc_open () 및 Posix_SetPriority () 와 함께 특정 PID에 맞게 조정할 수 있습니다. 이 기사는 실용적인 패러다임, 구덩이 포인트 및 문제 해결 제안을 제공합니다.
속임수 : UNIX와 같은 시스템에서 NICE 값 범위는 일반적으로 -20 (최우선 순위) ~ 19 (최저) 이고 기본값은 0입니다.
일반 사용자는 예를 들어 0 → 10에서 냉장 (우선 순위 감소) 만 증가시킬 수 있습니다 .
음수 값 (예 : -5)으로 우선 순위를 높이려면 일반적으로 루트 기능 또는 CAP_SYS_NICE가 필요합니다.
PCNTL_FORK ()를 사용하여 자식 프로세스를 도출 할 때 아동 프로세스 에서 Proc_Nice () 호출이 가장 직접적입니다. 예 : 학부모 절차는 작업을 담당하는 반면, 아동 프로세스는 많은 작업을 수행하지만 전반적인 상황을 늦추지 않도록 우선 순위를 줄입니다.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-keyword">declare</span></span><span>(strict_types=</span><span><span class="hljs-number">1</span></span><span>);
</span><span><span class="hljs-comment">// 확장자가 활성화되어 있는지 확인하십시오:pcntl、posix(선택 과목)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'pcntl_fork'</span></span><span>)) {
</span><span><span class="hljs-title function_ invoke__">fwrite</span></span><span>(STDERR, </span><span><span class="hljs-string">"pcntl 활성화되지 않았습니다,시연 할 수 없습니다\n"</span></span><span>);
</span><span><span class="hljs-keyword">exit</span></span><span>(</span><span><span class="hljs-number">1</span></span><span>);
}
</span><span><span class="hljs-variable">$pid</span></span><span> = </span><span><span class="hljs-title function_ invoke__">pcntl_fork</span></span><span>();
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$pid</span></span><span> === -</span><span><span class="hljs-number">1</span></span><span>) {
</span><span><span class="hljs-keyword">throw</span></span><span> </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-built_in">RuntimeException</span></span><span>(</span><span><span class="hljs-string">'fork 실패하다'</span></span><span>);
}
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$pid</span></span><span> === </span><span><span class="hljs-number">0</span></span><span>) {
</span><span><span class="hljs-comment">// --- 하위 프로세스 ---</span></span><span>
</span><span><span class="hljs-comment">// 할 것이다 niceness 기본적으로 0 조정 10(심지어“친숙한”,심지어低优先级)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">proc_nice</span></span><span>(</span><span><span class="hljs-number">10</span></span><span>)) {
</span><span><span class="hljs-comment">// 실패하다通常意味着권한不足或플랫폼不支持</span></span><span>
</span><span><span class="hljs-title function_ invoke__">fwrite</span></span><span>(STDERR, </span><span><span class="hljs-string">"[child] proc_nice 실패하다\n"</span></span><span>);
}
</span><span><span class="hljs-comment">// 시뮬레이션 CPU 집중적 인 작업</span></span><span>
</span><span><span class="hljs-variable">$sum</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>;
</span><span><span class="hljs-keyword">for</span></span><span> (</span><span><span class="hljs-variable">$i</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span> < </span><span><span class="hljs-number">5_000_000</span></span><span>; </span><span><span class="hljs-variable">$i</span></span><span>++) {
</span><span><span class="hljs-variable">$sum</span></span><span> += </span><span><span class="hljs-variable">$i</span></span><span>;
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"[child] done, sum=<span class="hljs-subst">{$sum}</span></span></span><span>\n";
</span><span><span class="hljs-keyword">exit</span></span><span>(</span><span><span class="hljs-number">0</span></span><span>);
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-comment">// --- 부모 과정 ---</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"[parent] fork 出하위 프로세스 PID=<span class="hljs-subst">{$pid}</span></span></span><span>\n";
</span><span><span class="hljs-comment">// 부모 과정继续高优先级工作(예를 들어 응답 HTTP 묻다)</span></span><span>
</span><span><span class="hljs-comment">// 等待하위 프로세스结束(生产环境선택 과목择不阻塞,또는 신호를 사용하십시오/콜백)</span></span><span>
</span><span><span class="hljs-title function_ invoke__">pcntl_wait</span></span><span>(</span><span><span class="hljs-variable">$status</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"[parent] child exit code = "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">pcntl_wexitstatus</span></span><span>(</span><span><span class="hljs-variable">$status</span></span><span>) . </span><span><span class="hljs-string">"\n"</span></span><span>;
}
</span></span>중요한 요점
Proc_nice ()는 현재 프로세스 에 영향을 미치므로 아동 프로세스 코드 경로 에서 호출되어야합니다.
양수 값 (예 : 10)으로 조정하려면 일반적으로 특권이 필요하지 않습니다. 음수 값을 설정하는 데 실패 할 수 있습니다.
단지 "하위 작업이 자원을 잡지 않도록하십시오"라는 경우 10 ~ 15 로 설정하면 종종 충분합니다.
포크를 사용하지 않고 다른 명령 (예 : FFMPEG , Convert 및 PHP와 같은 작업자를 직접 실행)을 시작하면 PID를 얻고 우선 순위를 조정해야합니다. Proc_get_status ()는 자식 프로세스 PID를 얻을 수 있습니다. 그런 다음 posix_setpriority () (posix Extension)를 사용하여 PID를보다 직관적으로 작동하십시오.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-keyword">declare</span></span><span>(strict_types=</span><span><span class="hljs-number">1</span></span><span>);
</span><span><span class="hljs-variable">$descriptorSpec</span></span><span> = [
</span><span><span class="hljs-number">0</span></span><span> => [</span><span><span class="hljs-string">'pipe'</span></span><span>, </span><span><span class="hljs-string">'r'</span></span><span>],
</span><span><span class="hljs-number">1</span></span><span> => [</span><span><span class="hljs-string">'pipe'</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>],
</span><span><span class="hljs-number">2</span></span><span> => [</span><span><span class="hljs-string">'pipe'</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>],
];
</span><span><span class="hljs-comment">// 예를 들어보세요:하나를 실행하십시오 CPU 밀집한 PHP 어린이 스크립트</span></span><span>
</span><span><span class="hljs-variable">$process</span></span><span> = </span><span><span class="hljs-title function_ invoke__">proc_open</span></span><span>(</span><span><span class="hljs-string">'php -r "usleep(3000000);"'</span></span><span>, </span><span><span class="hljs-variable">$descriptorSpec</span></span><span>, </span><span><span class="hljs-variable">$pipes</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">is_resource</span></span><span>(</span><span><span class="hljs-variable">$process</span></span><span>)) {
</span><span><span class="hljs-keyword">throw</span></span><span> </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-built_in">RuntimeException</span></span><span>(</span><span><span class="hljs-string">'proc_open 启动실패하다'</span></span><span>);
}
</span><span><span class="hljs-variable">$status</span></span><span> = </span><span><span class="hljs-title function_ invoke__">proc_get_status</span></span><span>(</span><span><span class="hljs-variable">$process</span></span><span>);
</span><span><span class="hljs-variable">$pid</span></span><span> = </span><span><span class="hljs-variable">$status</span></span><span>[</span><span><span class="hljs-string">'pid'</span></span><span>] ?? </span><span><span class="hljs-literal">null</span></span><span>;
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"child pid = <span class="hljs-subst">{$pid}</span></span></span><span>\n";
</span><span><span class="hljs-comment">// POSIX 방법:오른쪽 PID 설정 nice(범위 -20~19)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'posix_setpriority'</span></span><span>) && </span><span><span class="hljs-variable">$pid</span></span><span>) {
</span><span><span class="hljs-comment">// 할 것이다하위 프로세스调为 10(심지어低优先级)</span></span><span>
</span><span><span class="hljs-variable">$ok</span></span><span> = @</span><span><span class="hljs-title function_ invoke__">posix_setpriority</span></span><span>(</span><span><span class="hljs-number">10</span></span><span>, </span><span><span class="hljs-variable">$pid</span></span><span>, POSIX_PRIO_PROCESS);
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-variable">$ok</span></span><span>) {
</span><span><span class="hljs-title function_ invoke__">fwrite</span></span><span>(STDERR, </span><span><span class="hljs-string">"posix_setpriority 실패하다(권한/플랫폼/대상 프로세스 상태)\n"</span></span><span>);
}
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-comment">// 계획 B:외부 명령을 사용하십시오 renice(Linux/Unix)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$pid</span></span><span>) {
</span><span><span class="hljs-comment">// 알아채다:일부 환경에서는 필요할 수 있습니다 sudo 또는 특권</span></span><span>
@</span><span><span class="hljs-title function_ invoke__">shell_exec</span></span><span>(</span><span><span class="hljs-title function_ invoke__">sprintf</span></span><span>(</span><span><span class="hljs-string">'renice +10 -p %d 2>/dev/null'</span></span><span>, </span><span><span class="hljs-variable">$pid</span></span><span>));
}
}
</span><span><span class="hljs-comment">// 정리</span></span><span>
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$pipes</span></span><span>[</span><span><span class="hljs-number">0</span></span><span>]); </span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$pipes</span></span><span>[</span><span><span class="hljs-number">1</span></span><span>]); </span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$pipes</span></span><span>[</span><span><span class="hljs-number">2</span></span><span>]);
</span><span><span class="hljs-variable">$exitCode</span></span><span> = </span><span><span class="hljs-title function_ invoke__">proc_close</span></span><span>(</span><span><span class="hljs-variable">$process</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"child exit code = <span class="hljs-subst">{$exitCode}</span></span></span><span>\n";
</span></span>중요한 요점
Proc_open ()은 핸들을 반환하고 우선 순위를 자동으로 조정하지 않습니다. PID를 얻고 수동으로 처리해야합니다.
posix_setpriority () 는 Renice를 호출하는 것보다 제어 가능하며 분포에 대한 차이가 적지 만 Posix 확장을 활성화해야합니다.
컨테이너 또는 뿌리가 아닌 환경에있는 경우, 우선 순위를 높일 수 있습니다 (우선 순위 감소) .
PHP를 미세 조정할 필요가 없다면 우선 순위가 낮은 명령 줄 레벨에서 하위 프로세스를 직접 시작할 수도 있습니다.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-keyword">declare</span></span><span>(strict_types=</span><span><span class="hljs-number">1</span></span><span>);
</span><span><span class="hljs-comment">// CPU 친숙한:nice +10</span></span><span>
</span><span><span class="hljs-variable">$cmd</span></span><span> = </span><span><span class="hljs-string">'nice -n 10 php worker.php'</span></span><span>;
</span><span><span class="hljs-comment">// I/O 친숙한:ionice class 2(best-effort),level 7(가장 낮습니다)</span></span><span>
</span><span><span class="hljs-variable">$cmd</span></span><span> = </span><span><span class="hljs-string">'ionice -c 2 -n 7 nice -n 10 php worker.php'</span></span><span>;
</span><span><span class="hljs-variable">$proc</span></span><span> = </span><span><span class="hljs-title function_ invoke__">proc_open</span></span><span>(</span><span><span class="hljs-variable">$cmd</span></span><span>, [
</span><span><span class="hljs-number">0</span></span><span> => [</span><span><span class="hljs-string">'pipe'</span></span><span>, </span><span><span class="hljs-string">'r'</span></span><span>],
</span><span><span class="hljs-number">1</span></span><span> => [</span><span><span class="hljs-string">'pipe'</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>],
</span><span><span class="hljs-number">2</span></span><span> => [</span><span><span class="hljs-string">'pipe'</span></span><span>, </span><span><span class="hljs-string">'w'</span></span><span>],
], </span><span><span class="hljs-variable">$pipes</span></span><span>);
</span><span><span class="hljs-comment">// ... 省略与上文相同的정리逻辑</span></span><span>
</span></span>힌트
Ionice는 I/O 스케줄링 (디스크)에만 영향을 미치며 종종 NICE 와 결합되며 CPU + I/O 이중 전류 제한이 더 안정적입니다.
일부 컨테이너 최소 이미지에는 이온이 없을 수 있으며 이미지 (예 : Util-Linux 패키지)에 설치해야합니다.
반환 값과 경보를 감지하십시오
proc_nice ()는 true/false를 반환합니다. 실패하면 로그를 기록하고 posix_geteuid () , 대상 값 등과 같은 컨텍스트를 첨부하십시오.
posix_setpriority () 마찬가지로, 유사하게, 실패는 권한이 없을 때 일반적이며 PID가 종료되었습니다 .
실제 우선 순위를 기록하십시오
Linux는 /proc/<pid>/stat 의 멋진 필드를 읽거나 ps -o pid, ni, cmd -p <pid> 확인을 호출 할 수 있습니다.
PHP에서는 ( 'ps -o pid, ni, cmd -p'. (int) $ pid, $ out)를 실행 하고 결과를 기록 할 수 있습니다.
계층 적 전류 제한
그것은 Nice Alone의 CPU 경쟁 에만 효과적입니다. 동시성이 여전히 급증하는 경우 큐/토큰 버킷 (예 : Redis + Lua)과 프로세스의 상한을 중첩하십시오.
Linux/UNIX :이 기사의 방법은 적용됩니다. 불평등받지 않은 사용자는 단지 훌륭함을 증가시킬 수 있습니다 ( "더 나은 대화"가됩니다).
컨테이너/시스템 서비스 : 서비스가 SystemD에 의해 관리되는 경우 UNIT 파일에서 nice =를 설정하거나 avientCapabilities = cap_sys_nice를 설정할 수 있습니다. 컨테이너는 런닝 매개 변수에 -cap-add sys_nice를 추가 할 수 있습니다.
MACOS : 시맨틱은 Linux와 유사하며 Renice 및 Posix 인터페이스를 사용할 수 있습니다.
Windows : Proc_nice ()는 사용 가능하지 않거나 효과적이지 않습니다 (일반적으로 실패 및 트리거 경고). Windows의 우선 순위는 Proc_open () + WMIC /PowerShell 또는 FFI를 통해 조정해야합니다. 그것은 다른 구현 경로 에 속하며이 기사와 동일한 규칙 세트가 아닙니다.
아동 과정 내부 : pcntl_fork () → 아동 프로세스 Proc_nice (10 ~ 15) .
외부 명령 : proc_open () → proc_get_status ()를 얻으려면 pid → posix_setpriority ($ nice, $ pid, posix_prio_process)를 얻습니다.
셔틀 : 명령 전에 멋진 -n <n>을 추가하면 I/O가 이온이 조밀하게 쌓입니다.
권한 : 음수 값에는 특권이 필요합니다. 컨테이너에 sys_nice 기능을 추가하거나 양수 값을 사용하는 것을 고려하십시오.
확인 : ps 또는 read /proc를 사용하여 확인하십시오. 쉽게 추적 할 수 있도록 로그가 기록됩니다.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-keyword">declare</span></span><span>(strict_types=</span><span><span class="hljs-number">1</span></span><span>);
<span class="hljs-comment">/**
* 할 것이다指定 PID 과정 niceness 조정目标值(기본 10)。
* 반품 true 표현하다“성공적으로 보입니다”(최종 효과를 보장하지 않습니다,결합해야합니다 ps 확인하다)。
*/</span>
</span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">lower_priority</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-keyword">int</span></span></span><span> </span><span><span class="hljs-variable">$pid</span></span><span>, </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$nice</span></span><span> = </span><span><span class="hljs-number">10</span></span><span>): </span><span><span class="hljs-title">bool</span></span><span>
{
</span><span><span class="hljs-comment">// Border Guardrail</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$nice</span></span><span> < -</span><span><span class="hljs-number">20</span></span><span> || </span><span><span class="hljs-variable">$nice</span></span><span> > </span><span><span class="hljs-number">19</span></span><span>) {
</span><span><span class="hljs-keyword">throw</span></span><span> </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-built_in">InvalidArgumentException</span></span><span>(</span><span><span class="hljs-string">'nice 들어 있어야합니다 -20..19 ~ 사이'</span></span><span>);
}
</span><span><span class="hljs-comment">// 첫 번째 선택 POSIX API</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">function_exists</span></span><span>(</span><span><span class="hljs-string">'posix_setpriority'</span></span><span>)) {
</span><span><span class="hljs-variable">$ok</span></span><span> = @</span><span><span class="hljs-title function_ invoke__">posix_setpriority</span></span><span>(</span><span><span class="hljs-variable">$nice</span></span><span>, </span><span><span class="hljs-variable">$pid</span></span><span>, POSIX_PRIO_PROCESS);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$ok</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-literal">true</span></span><span>;
}
}
</span><span><span class="hljs-comment">// 대안:renice(오직 *nix)</span></span><span>
</span><span><span class="hljs-variable">$ret</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>;
@</span><span><span class="hljs-title function_ invoke__">exec</span></span><span>(</span><span><span class="hljs-title function_ invoke__">sprintf</span></span><span>(</span><span><span class="hljs-string">'renice %s%d -p %d 2>/dev/null'</span></span><span>,
</span><span><span class="hljs-variable">$nice</span></span><span> >= </span><span><span class="hljs-number">0</span></span><span> ? </span><span><span class="hljs-string">'+'</span></span><span> : </span><span><span class="hljs-string">''</span></span><span>, </span><span><span class="hljs-variable">$nice</span></span><span>, </span><span><span class="hljs-variable">$pid</span></span><span>
), </span><span><span class="hljs-variable">$out</span></span><span>, </span><span><span class="hljs-variable">$ret</span></span><span>);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$ret</span></span><span> === </span><span><span class="hljs-number">0</span></span><span>;
}
</span></span>