Maison  >  Article  >  cadre php  >  PHP multi-processus et interruption de signal réalise une gestion de la mémoire résidente multi-tâches [modèle Master/Worker]

PHP multi-processus et interruption de signal réalise une gestion de la mémoire résidente multi-tâches [modèle Master/Worker]

藏色散人
藏色散人avant
2019-10-02 17:37:442462parcourir

Cet article est basé sur des tests multi-processus effectués par l'extension pcntl.

Stratégie de planification des processus

Le système d'exploitation est responsable de la planification des processus parents et enfants. La planification spécifique du processus enfant ou du processus parent est déterminée en premier par. l'algorithme de planification du système. Bien sûr, cela peut être fait dans le processus parent. Ajouter un délai au processus ou appeler la fonction de recyclage de processus pcntl_wait peut permettre au processus enfant de s'exécuter en premier. lorsque le processus est créé pour l'empêcher de devenir un processus zombie.

Signal :

Le signal est appelé système d'interruption logicielle ou interruption logicielle, et sa fonction est d'envoyer des notifications d'événements asynchrones au processus.

Numéro de signal : [Le code source est basé sur les signaux SIGINT, SIGTERM, SIGUSR1. Veuillez consulter le manuel de la commande kill pour connaître la signification, qui n'est pas décrite]

. Linux en prend en charge 64, dont la moitié sont des signaux en temps réel. Ces signaux ont leurs propres nombres et valeurs entières correspondantes. Pour la signification du numéro de chaque signal, les lecteurs peuvent se référer au manuel Linux correspondant [manuel manuel pour le savoir]

Fonction de traitement du signal :

Les signaux sont généralement liés aux fonctions correspondantes, certains ont des actions par défaut telles que SIGKILL, SIGTERM et SIGINT. L'opération par défaut consiste à tuer le processus. Bien sûr, nous pouvons le remplacer en le remplaçant via pcntl_signal.

Le concept de signal : C'est la même chose que l'interruption matérielle. Veuillez vous référer à mes articles précédents ou vérifier le principe de l'interruption matérielle de la puce.

Envoi de signal :

processus de numéro de signal d'arrêt ou signal d'interruption du produit clé ou vous pouvez utiliser posix_kill et d'autres fonctions dans le code source.

Les processus sont isolés les uns des autres et disposent de leur propre espace de pile. En plus d'un texte commun [zone de code], ils ont également leur propre code exécutable. Lorsque le processus est en cours d'exécution, il occupera des ressources CPU et. les autres processus n'y auront pas accès. Droit d'exécution, à ce moment-là, les autres processus seront dans un état bloqué [comme le service TCP mentionné précédemment]. Lorsque le processus se terminera [exécutera jusqu'à la dernière phrase du code ou rencontrera un retour]. ou quittez, quittez la fonction de processus ou rencontrez Il se terminera lorsqu'un événement de signal se produit] Renoncez aux autorisations et libérez de la mémoire, et d'autres processus auront la possibilité de s'exécuter.

Le processus a son propre descripteur de processus, dont le numéro de processus PID est plus couramment utilisé. Lorsque le processus est en cours d'exécution, le fichier de processus correspondant sera généré sous le système /proc/PID, et l'utilisateur pourra le faire. voir par lui-même.

Chaque processus a son propre groupe de processus [ensemble de processus]. Une collection de plusieurs groupes de processus est une session. La création d'une session est créée via un processus, et ce processus ne peut pas être le processus chef de groupe. Le processus deviendra le premier processus de la session et deviendra également le leader du groupe de processus. En même temps, il quittera le terminal de contrôle. Même si le processus précédent est lié au terminal de contrôle, il quittera le processus. [Création d'un processus démon].

Masque d'autorisation de description de fichier [mot de masque d'autorisation] :

umask () Vous pouvez exécuter cette commande sous Linux, puis créer le fichier et afficher ses autorisations [Si vous ne trouvez rien après avoir couru, cela signifie que vous ne vous êtes pas suffisamment entraîné^_^]

<?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__,&#39;workerHandleSignal&#39;],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__,&#39;handleMasterSignal&#39;],false);
        pcntl_signal(SIGTERM,[__CLASS__,&#39;handleMasterSignal&#39;],false);
        pcntl_signal(SIGUSR1,[__CLASS__,&#39;handleMasterSignal&#39;],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 &#39;vendor/autoload.php&#39;;
$process = new \Chen\Worker\Server();
$process->workerJob = [new \Chen\Worker\Talk(),new \Chen\Worker\Job()];
$process->run();

PHP multi-processus et interruption de signal réalise une gestion de la mémoire résidente multi-tâches [modèle Master/Worker]

Pour plus d'articles techniques liés à Laravel, veuillez visiter Laravel Framework Tutoriel de mise en route colonne pour apprendre !

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