Maison > Article > développement back-end > Explication détaillée de la communication inter-processus PHP
Un processus est une activité en cours d'exécution d'un programme avec des fonctions indépendantes sur une certaine collection de données. En d’autres termes, il s’agit de l’unité de base d’un programme lorsque le système planifie plusieurs CPU. Le processus n'est pas un concept étranger à la plupart des langages, et en tant que « meilleur langage au monde, PHP » est certainement une exception.
Le processus en php se réalise sous forme d'extensions. 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 : complétez l'API commune pour les machines compatibles Posix, comme l'obtention de l'identifiant du processus, la suppression du processus, etc.
extension sysvmsg : une file d'attente de messages qui implémente la communication inter-processus système v.
Extension sysvsem : implémente le sémaphore système v.
extension sysvshm : implémente la mémoire partagée du 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+.
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.
$parentPid = posix_getpid(); 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.
4. Communication inter-processus (IPC)
Les méthodes de communication de processus sous Linux incluent généralement : la file d'attente de messages, le sémaphore, la mémoire partagée, le signal, le canal et le socket.
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.
$parentPid = posix_getpid(); 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";
Puisqu'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, plusieurs processus sont créés pour modifier la même valeur en mémoire.
$parentPid = posix_getpid(); 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.
$parentPid = posix_getpid(); 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 (pipes nommés)
Les pipes sont un moyen couramment utilisé de communication multi-processus. Les pipes sont divisées en pipes sans nom et les pipes sans nom ne peuvent être utilisées. avec des relations de parenté, la communication inter-processus et 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); } }
Recommandations associées :
Comment implémenter le verrouillage du processus PHP
Résumé des points à noter sur le processus PHP communication
Communication sémaphore et mémoire partagée basée sur la communication de processus 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!