Maison > Article > développement back-end > Découvrez les processus et la communication inter-processus en PHP dans un seul article
Cet article vous amènera à comprendre le processus et la communication inter-processus en 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 sera utile à tout le monde.
Environnement
Le processus en php se réalise sous la forme d'une extension. Grâce à ces extensions, nous pouvons facilement réaliser une série d’actions dans le processus.
Extension pcntl : L'extension du processus principal, le processus d'achèvement est créé dans l'opération d'attente. Extension Posix : API générale complète de la machine compatible Posix, telle que l'obtention de l'identifiant du processus, la suppression du processus, etc. Extension sysvmsg : file d'attente de messages qui implémente la communication inter-processus en mode système v. Extension sysvsem : implémente les sémaphores en mode système v. Extension sysvshm : implémente la mémoire partagée en mode système v. Extension Sockets : implémente la communication socket. Ces extensions ne peuvent être utilisées que sous Linux/Mac et ne sont pas prises en charge sous Windows. Enfin, il est recommandé que la version PHP soit 5.5+.
Exemple simple
Un exemple simple multi-processus PHP Dans cet exemple, il y a un processus enfant et un processus parent. Le processus enfant génère 5 fois et quitte le programme.
echo "parent progress pid:{$parentPid}\n"; $childList = array(); $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 $pid = posix_getpid(); $repeatNum = 5; for ( $i = 1; $i <= $repeatNum; $i++) { echo "({$pid})child progress is running! {$i} \n"; $rand = rand(1,3); sleep($rand); } exit("({$pid})child progress end!\n"); } else { // 父进程执行程序 $childList[$pid] = 1; } // 等待子进程结束 pcntl_wait($status); echo "({$parentPid})main progress end!";
Parfait, j'ai enfin créé un processus enfant et un processus parent. C'est fini ? Non, chaque processus est indépendant les uns des autres, il n’y a pas d’intersection et le champ d’utilisation est sévèrement limité. Que faire ? Utilisons la communication inter-progrès.
Communication inter-processus (IPC)
Habituellement, les méthodes de communication de processus sous Linux incluent : la file d'attente de messages, le sémaphore, la mémoire partagée, le signal, Tuyaux, prises.
1. File d'attente des messages
La file d'attente des messages est une file d'attente stockée en mémoire. Le code suivant créera 3 sous-processus producteurs et 2 sous-processus consommateurs. Ces 5 processus communiqueront via la file d'attente des messages.
echo "parent progress pid:{$parentPid}\n";$childList = array(); // 创建消息队列,以及定义消息类型(类似于数据库中的库) $id = ftok(__FILE__,'m'); $msgQueue = msg_get_queue($id); const MSG_TYPE = 1; // 生产者 function producer(){ global $msgQueue; $pid = posix_getpid(); $repeatNum = 5; for ( $i = 1; $i <= $repeatNum; $i++) { $str = "({$pid})progress create! {$i}"; msg_send($msgQueue,MSG_TYPE,$str); $rand = rand(1,3); sleep($rand); } } // 消费者 function consumer(){ global $msgQueue; $pid = posix_getpid(); $repeatNum = 6; for ( $i = 1; $i <= $repeatNum; $i++) { $rel = msg_receive($msgQueue,MSG_TYPE,$msgType,1024,$message); echo "{$message} | consumer({$pid}) destroy \n"; $rand = rand(1,3); sleep($rand); } } function createProgress($callback){ $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 $pid = posix_getpid(); $callback(); exit("({$pid})child progress end!\n"); }else{ // 父进程执行程序 return $pid; } } // 3个写进程 for ($i = 0; $i < 3; $i ++ ) { $pid = createProgress('producer'); $childList[$pid] = 1; echo "create producer child progress: {$pid} \n"; } // 2个写进程 for ($i = 0; $i < 2; $i ++ ) { $pid = createProgress('consumer'); $childList[$pid] = 1; echo "create consumer child progress: {$pid} \n"; } // 等待所有子进程结束 while(!empty($childList)){ $childPid = pcntl_wait($status); if ($childPid > 0){ unset($childList[$childPid]); } } echo "({$parentPid})main progress end!\n";
Étant donné qu'un seul processus peut accéder aux données dans la file d'attente des messages, aucun verrou ou sémaphore supplémentaire n'est nécessaire.
2. Sémaphore et mémoire partagée
Sémaphore : C'est une opération atomique fournie par le système, un sémaphore, et seul votre processus peut l'opérer en même temps . Lorsqu'un processus obtient un sémaphore, celui-ci doit être libéré par le processus.
Mémoire partagée : Il s'agit d'une zone mémoire commune ouverte par le système dans la mémoire. N'importe quel processus peut y accéder en même temps, plusieurs processus peuvent accéder à cette zone. il est nécessaire de verrouiller ou de sémaphorer cette zone mémoire.
Ci-dessous, créez plusieurs processus pour modifier la même valeur en mémoire.
echo "parent progress pid:{$parentPid}\n"; $childList = array(); // 创建共享内存,创建信号量,定义共享key $shm_id = ftok(__FILE__,'m'); $sem_id = ftok(__FILE__,'s'); $shareMemory = shm_attach($shm_id); $signal = sem_get($sem_id); const SHARE_KEY = 1; // 生产者 function producer(){ global $shareMemory; global $signal; $pid = posix_getpid(); $repeatNum = 5; for ( $i = 1; $i <= $repeatNum; $i++) { // 获得信号量 sem_acquire($signal); if (shm_has_var($shareMemory,SHARE_KEY)){ // 有值,加一 $count = shm_get_var($shareMemory,SHARE_KEY); $count ++; shm_put_var($shareMemory,SHARE_KEY,$count); echo "({$pid}) count: {$count}\n"; }else{ // 无值,初始化 shm_put_var($shareMemory,SHARE_KEY,0); echo "({$pid}) count: 0\n"; } // 用完释放 sem_release($signal); $rand = rand(1,3); sleep($rand); } } function createProgress($callback){ $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 $pid = posix_getpid(); $callback(); exit("({$pid})child progress end!\n"); }else{ // 父进程执行程序 return $pid; } } // 3个写进程 for ($i = 0; $i < 3; $i ++ ) { $pid = createProgress('producer'); $childList[$pid] = 1; echo "create producer child progress: {$pid} \n"; } // 等待所有子进程结束 while(!empty($childList)){ $childPid = pcntl_wait($status); if ($childPid > 0){ unset($childList[$childPid]); } } // 释放共享内存与信号量 shm_remove($shareMemory); sem_remove($signal); echo "({$parentPid})main progress end!\n";
3. Signal
Un signal est un appel système. Habituellement, la commande kill que nous utilisons consiste à envoyer un certain signal à un certain processus. Vous pouvez vérifier les signaux spécifiques en exécutant kill -l dans liunx/mac. Dans l'exemple suivant, le processus parent attend 5 secondes et envoie le signal sigint au processus enfant. Le processus enfant capture le signal et le traite avec la fonction de traitement du signal.
echo "parent progress pid:{$parentPid}\n"; // 定义一个信号处理函数 function sighandler($signo) { $pid = posix_getpid(); echo "{$pid} progress,oh no ,I'm killed!\n"; exit(1); } $pid = pcntl_fork(); if ( $pid == -1) { // 创建失败 exit("fork progress error!\n"); } else if ($pid == 0) { // 子进程执行程序 // 注册信号处理函数 declare(ticks=10); pcntl_signal(SIGINT, "sighandler"); $pid = posix_getpid(); while(true){ echo "{$pid} child progress is running!\n"; sleep(1); } exit("({$pid})child progress end!\n"); }else{ // 父进程执行程序 $childList[$pid] = 1; // 5秒后,父进程向子进程发送sigint信号. sleep(5); posix_kill($pid,SIGINT); sleep(5); } echo "({$parentPid})main progress end!\n";
4. Pipes (canaux nommés)
Les tuyaux sont un moyen couramment utilisé de communication multi-processus. Les tuyaux sont divisés en tuyaux sans nom et en tuyaux sans nom. ne peut être utilisé que pour la communication entre processus avec affinité, les canaux nommés peuvent être utilisés pour n'importe quel processus sur le même hôte. Seules les chaînes célèbres sont présentées ici. Dans l'exemple suivant, le processus enfant écrit des données et le processus parent lit les données.
$pipe_path = '/data/test.pipe'; if(!file_exists($pipe_path)){ if(!posix_mkfifo($pipe_path,0664)){ exit("create pipe error!"); } } $pid = pcntl_fork(); if($pid == 0){ // 子进程,向管道写数据 $file = fopen($pipe_path,'w'); while (true){ fwrite($file,'hello world'); $rand = rand(1,3); sleep($rand); } exit('child end!'); }else{ // 父进程,从管道读数据 $file = fopen($pipe_path,'r'); while (true){ $rel = fread($file,20); echo "{$rel}\n"; $rand = rand(1,2); sleep($rand); } }
Étude recommandée : "Tutoriel vidéo PHP"
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!