Position actuelle: Accueil> Derniers articles> Vous voulez contrôler la priorité des processus enfants? Voir comment utiliser proc_nice pour l'implémenter en php

Vous voulez contrôler la priorité des processus enfants? Voir comment utiliser proc_nice pour l'implémenter en php

gitbox 2025-08-26

Dans les scénarios de traitement de la concurrence ou des lots élevés, nous ne voulons souvent pas que certaines tâches de fond «mangent» le CPU et affectent la réponse aux services externes. Le système d'exploitation a donné la priorité à l'ajustement du processus actuel; Pour contrôler le processus de l'enfant , vous pouvez l'appeler dans le processus de l'enfant de Fork ou l'ajuster pour un PID spécifique en combinaison avec Proc_Open () et POSIX_SETPRIORITY () . Cet article donne des paradigmes pratiques, des points de stand et des suggestions de dépannage.

Cheat: Sur les systèmes de type UNIX, la plage de valeurs Nice est généralement -20 (priorité la plus élevée) à 19 (la plus basse) , et la valeur par défaut est 0.

  • Les utilisateurs ordinaires ne peuvent qu'augmenter la gentillesse (réduire la priorité) , par exemple, à partir de 0 → 10.

  • L'augmentation de la priorité à une valeur négative (telle que -5) nécessite généralement une capacité racine ou CAP_SYS_NICE .


Scénario 1: après pcntl_fork () , "dépréciser et exécuter" dans le processus de l'enfant

Lorsque vous utilisez pcntl_fork () pour dériver un processus enfant, appeler proc_nice () dans le processus enfant est le plus direct. Exemple: Le processus parent est responsable de prendre des emplois, tandis que le processus de l'enfant fait un travail lourd mais réduit la priorité pour éviter de ralentir la situation globale.

 <span><span><span class="hljs-meta">&lt;?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">// Assurez-vous que l&#39;extension est activée:pcntl、posix(Facultatif)</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 Non activé,Incapable de démontrer\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 échouer'</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">// --- Sous-processus ---</span></span><span>
    </span><span><span class="hljs-comment">// Volonté niceness À partir de défaut 0 Ajusté à 10(Même“amical”,Même低优先级)</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">// échouer通常意味着Autorisation不足或plate-forme不支持</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 échouer\n"</span></span><span>);
    }

    </span><span><span class="hljs-comment">// simulation CPU Travail intensif</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> &lt; </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">// --- Processus parental ---</span></span><span>
    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"[parent] fork 出Sous-processus PID=<span class="hljs-subst">{$pid}</span></span></span><span>\n";
    </span><span><span class="hljs-comment">// Processus parental继续高优先级工作(Par exemple, réponse HTTP demander)</span></span><span>
    </span><span><span class="hljs-comment">// 等待Sous-processus结束(生产环境Facultatif择不阻塞,Ou utiliser un signal/Rappel)</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>

Points importants

  1. proc_nice () affecte le processus actuel , il doit donc être appelé dans le chemin du code du processus de l'enfant .

  2. L'ajustement à une valeur positive (comme 10) ne nécessite généralement pas de privilèges; La définition d'une valeur négative peut échouer.

  3. Si vous «laissez la sous-tâche ne sais pas les ressources», la définir à 10 ~ 15 suffit souvent.


Scénario 2: proc_open () démarre une commande externe et ajuste sa priorité

Si vous n'utilisez pas Fork , mais démarrez d'autres commandes (telles que FFMPEG , Convert et PHP pour exécuter le travailleur par vous-même), vous devez obtenir le PID et ajuster la priorité. proc_get_status () peut obtenir le processus enfant PID; Utilisez ensuite POSIX_SETPRIORITY () (extension POSIX) pour faire fonctionner le PID plus intuitivement.

 <span><span><span class="hljs-meta">&lt;?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> =&gt; [</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> =&gt; [</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> =&gt; [</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">// Donner un exemple:Courir un CPU Dense PHP Script enfant</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 启动échouer'</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 Chemin:Droite PID installation nice(portée -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>) &amp;&amp; </span><span><span class="hljs-variable">$pid</span></span><span>) {
    </span><span><span class="hljs-comment">// VolontéSous-processus调为 10(Même低优先级)</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 échouer(Autorisation/plate-forme/État du processus cible)\n"</span></span><span>);
    }
} </span><span><span class="hljs-keyword">else</span></span><span> {
    </span><span><span class="hljs-comment">// plan B:Utiliser des commandes externes 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">// Avis:Dans certains environnements, il peut être nécessaire sudo ou privilège</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&gt;/dev/null'</span></span><span>, </span><span><span class="hljs-variable">$pid</span></span><span>));
    }
}

</span><span><span class="hljs-comment">// Nettoyer</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>

Points importants

  • proc_open () renvoie une poignée et n'ajuste pas automatiquement la priorité. Vous devez obtenir le PID et le traiter manuellement.

  • POSIX_SETPRIORITY () est plus contrôlable que d'appeler Renice et a moins de différences entre les distributions, mais nécessite l'activation de l'extension POSIX .

  • Si vous êtes dans un environnement de conteneur ou de non-racine, vous ne pouvez augmenter que la gentillesse (réduire la priorité) .


Scénario 3: Utilisez bien / ionice directement pour démarrer (le plus rapide)

Si vous n'avez pas besoin de vous affiner en PHP, vous pouvez également lancer directement le sous-processus au niveau de la ligne de commande avec une faible priorité:

 <span><span><span class="hljs-meta">&lt;?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 amical: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 amical:ionice class 2(best-effort),level 7(le plus bas)</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> =&gt; [</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> =&gt; [</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> =&gt; [</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">// ... 省略与上文相同的Nettoyer逻辑</span></span><span>
</span></span>

indice

  • Ionice n'affecte que la planification des E / S (disque), est souvent combiné avec de beaux , et la limite de courant à double E / S CPU + est plus stable.

  • Certaines images minimales de conteneur peuvent ne pas avoir d'ionice et doivent être installées dans l'image (comme le package Util-Linux ).


Gestion des erreurs et observabilité

  1. Détecter la valeur de retour et l'alarme

    • proc_nice () renvoie true / false . Si vous échouez, veuillez enregistrer le journal et joindre le contexte tel que POSIX_GETEUID () , la valeur cible, etc.

    • POSIX_SETPRIORITY () De même, les échecs sont communs en l'absence d'autorisations et le PID a été quitté .

  2. Enregistrez la priorité réelle

    • Linux peut lire le champ sympa de / proc / <pid> / stat , ou appeler ps -o pid, ni, cmd -p <pid> vérification.

    • Dans PHP, vous pouvez exécuter ('ps -o pid, ni, cmd -p'. (Int) $ pid, $ out) et enregistrer le résultat.

  3. Limite de courant hiérarchique

    • Il n'est efficace que pour la compétition CPU par Nice seul; S'il y a encore une vague de concurrence , veuillez superposer le seau de file d'attente / jeton (comme redis + Lua) et la limite supérieure du processus .


Détails de la plate-forme et de l'autorisation

  • Linux / Unix : la méthode de cet article est applicable. Les utilisateurs non privilégiés ne peuvent qu'augmenter la gentillesse (devenir «meilleur discours»).

  • Service de conteneur / système : Si le service est géré par SystemD, vous pouvez définir Nice = dans le fichier unitaire ou Grant AmbientCapabilities = CAP_SYS_NICE . Le conteneur peut être ajouté --CAP-ADD SYS_NICE aux paramètres d'exécution.

  • MacOS : La sémantique est similaire aux interfaces Linux, Renice et POSIX sont disponibles.

  • Windows : Proc_Nice () n'est pas disponible / non efficace (généralement, une défaillance de retour et un avertissement de déclenchement). La priorité de Windows doit être ajustée via Proc_Open () + WMIC / PowerShell ou FFI. Il appartient à différents chemins d'implémentation et n'est pas dans le même ensemble de règles que cet article.


Suggestions pratiques (notes courtes)

  • À l'intérieur du processus de l'enfant : pcntl_fork () → Processus de l'enfant proc_nice (10 ~ 15) .

  • Commande externe : proc_open ()proc_get_status () pour obtenir pid → posix_setpriority ($ nice, $ pid, posix_prio_process) .

  • Une navette : Ajoutez Nice -n <n> avant la commande, et les E / S sont densément empilées avec Ionice .

  • Autorisations : les valeurs négatives nécessitent des privilèges; Envisagez d'ajouter des capacités SYS_NICE ou en utilisant des valeurs positives dans le conteneur.

  • Vérification : utilisez ps ou lisez / proc pour vérifier; Les journaux sont enregistrés pour une traçabilité facile.


Extrait de référence: encapsuler une fonction de gadget "Processus de dépréciation"

 <span><span><span class="hljs-meta">&lt;?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">/**
 * Volonté指定 PID Le processus niceness Ajusté à目标值(défaut 10)。
 * retour true exprimer“Semble réussir”(Aucune garantie l&#39;effet final,Besoin d&#39;être combiné ps vérifier)。
 */</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">// Garde-corps</span></span><span>
    </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$nice</span></span><span> &lt; -</span><span><span class="hljs-number">20</span></span><span> || </span><span><span class="hljs-variable">$nice</span></span><span> &gt; </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 Doit être dans -20..19 entre'</span></span><span>);
    }

    </span><span><span class="hljs-comment">// Premier choix 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">// Alternative:renice(seulement *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&gt;/dev/null'</span></span><span>,
        </span><span><span class="hljs-variable">$nice</span></span><span> &gt;= </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>