高い並行性またはバッチ処理シナリオでは、いくつかのバックグラウンドタスクがCPUを「食べる」ことを望まないことが多く、外部サービスへの応答に影響を与えません。オペレーティングシステムは、現在のプロセスを調整するための優先順位を提供しています。子のプロセスを制御するには、フォークチャイルドプロセスで呼び出すか、 proc_open()およびposix_setpriority()と組み合わせて特定のPIDに対して調整することができます。この記事では、実用的なパラダイム、ピットポイント、トラブルシューティングの提案を示します。
チート:Unixのようなシステムでは、値の範囲は通常-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 、変換、PHPなどのワーカーを自分で実行する)を開始する場合は、PIDを取得して優先度を調整する必要があります。 proc_get_status()は、子プロセスpidを取得できます。次に、POSIX_SETPRIORITY() (POSIX拡張子)を使用して、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">// 例を挙げてください:1つを実行します 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>
ヒント
イオンは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では、 exec( 'ps -o pid、ni、cmd -p'。(int)$ pid、$ out)を実行し、結果を記録できます。
階層電流制限
Nice AloneによるCPU競争にのみ効果的です。並行性にまだ急増している場合は、キュー/トークンバケット(Redis + Luaなど)とプロセスの上限を重ねてください。
Linux/unix :この記事のメソッドが適用されます。非主要なユーザーは、素晴らしさを高めることしかできません(「より良い話」になります)。
コンテナ/システムサービス:サービスがSystemDによって管理されている場合、ユニットファイルまたはgrant Ambientcapability = cap_sys_niceでnice =を設定できます。コンテナを追加することができます - 実行中のパラメーターに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">// ボーダーガードレール</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>