Maison  >  Article  >  développement back-end  >  Exemple de code pour la gestion des processus PHP

Exemple de code pour la gestion des processus PHP

不言
不言avant
2018-11-17 17:14:411814parcourir

Cet article vous apporte des exemples de code sur la gestion des processus PHP. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

Cet article est un complément et une amélioration de l'article précédent. Créez un processus maître, installez une minuterie dans le processus maître, détectez la longueur de la file d'attente toutes les 5 minutes et calculez-la en fonction de la longueur de la file d'attente. . Le processus de travail requis,

puis créez ou tuez le processus enfant. L’avantage est d’éviter que la file d’attente ne s’accumule et que les tâches ne soient pas traitées à temps. Pour mettre à jour le code métier, seule l'opération de rechargement est requise.

L'ensemble du processus comporte les points de connaissance suivants :

  • Étapes pour créer un démon :

  1. Paramètres Autorisations de fichier par défaut

  2. fork un processus, le processus parent se termine

  3. Appelez setsid pour créer une nouvelle session

  4. Remplacez le répertoire de travail actuel par le répertoire racine

  5. Fermer les descripteurs de fichiers qui ne sont plus nécessaires

  • Utiliser le minuteur d'implémentation du signal

Le minuteur de l'article précédent dépend des tâches planifiées du système. Cette fois, il est implémenté à l'aide du signal de réveil. Les versions inférieures à PHP 5.3.0 dépendent des ticks, 5.3. .0 et la version ci-dessus peuvent utiliser pcntl_signal_dispatch

Signal : fournit une méthode de traitement d'événement asynchrone lorsqu'un signal se produit, le processus dispose des trois manières suivantes pour traiter le signal

  1. <.>Ignorer ce signal

  2. Capter le signal

  3. Effectuer l'action par défaut du système pour la plupart des signaux est de terminer le processus<.>

    Signaux communs
  • SIGKILL, SIGSTOP sont deux signaux qui ne peuvent être ignorés et capturés par les utilisateurs

SIGINT( 2) : signal de fin de programme, généralement émis lorsque Ctrl-C), utilisé pour notifier au groupe de processus de premier plan de terminer le processus

SIGQUIT (3) : similaire à SIGINT, mais est signalé par QUIT caractère (généralement Ctrl+/) Contrôle. Lorsque le processus reçoit ce message et se termine, il génère un fichier principal

SIGKILL(9) : terminez le processus immédiatement et ne peut pas être ignoré ou bloqué

SIGUSR1(10) : Signal défini par l'utilisateur

SIGUSR2(12) : réservé aux utilisateurs

SIGALRM(14) : signal de réveil

SIGTERM(15) : terminer le processus et peuvent être capturés par le programme afin que le processus puisse être complété par des opérations de nettoyage.

SIGSTOP(19) : Arrêter un processus. Le processus n'est pas encore terminé. Il suspend simplement l'exécution

    Empêcher la génération de processus zombies
  • Tous les processus deviendront des processus zombies à leur sortie. À ce moment, si le processus parent est toujours en cours d'exécution et que wait ou waitpid n'est pas appelé, les ressources occupées par le processus zombie ne seront pas nettoyées. Le processus parent a été terminé, le processus zombie sera appelé par le processus d'initialisation pour effectuer le nettoyage.

Déployez le code métier, le code principal est le suivant

 

Une chose à noter est que lors de la création d'un processus démon pour fermer les entrées et sorties, ainsi que le flux de sortie d'erreur, s'il y a un écho, etc. derrière les caractères de sortie du code, une erreur fatale se produira et le flux de sortie doit être redirigé vers /dev/null dans le code php. Ou rediriger lorsque le terminal démarre le processus

<?php
define(&#39;PROC_MAX&#39;, 10);
define(&#39;PROC_MIN&#39;, 5);

$cmd = $argv[1];
$aPid = [];
$pidFile = __DIR__ . &#39;/pid.pid&#39;;
$pid = file_get_contents($pidFile);

switch($cmd){
    case &#39;start&#39; :
        if(posix_kill($pid, 0)){
            echo "gamelog process is already exsits!\n";
            return false;
        }
        //设置默认文件权限
        umask(022);
        //fork
        $pid = pcntl_fork();
        if($pid < 0){
            exit(&#39;fork error!&#39;);
        }else if($pid > 0){
            exit;
        }
        //脱离当前终端
        posix_setsid();
        //将当前工作目录更改为根目录
        chdir(&#39;/&#39;);
        //关闭文件描述符
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);
        //重定向输入输出
        global $STDOUT, $STDERR;
        $STDOUT = fopen(&#39;/dev/null&#39;, &#39;a&#39;);
        $STDERR = fopen(&#39;/dev/null&#39;, &#39;a&#39;);
        
        cli_set_process_title(&#39;gamelog:master&#39;);
        $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(&#39;fork error!&#39;);
                    } else if ($pid == 0) {
                        cli_set_process_title(&#39;gamelog:worker&#39;);
                        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 &#39;stop&#39; :
        if(!posix_kill($pid, SIGUSR1)){
            exit(&#39;stop gamelog process error!&#39;);
        }
        break;
    case &#39;reload&#39; :
        if(!posix_kill($pid, SIGUSR2)){
            exit(&#39;restop gamelog process error!&#39;);
        }
        break;
    default :
        echo "Useage php signal.php start|stop|reload\n";
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer