Introduction : pourquoi la concurrence en PHP n'est pas un mythe
\nPHP est traditionnellement considéré comme un langage synchrone, où chaque requête est traitée séquentiellement. Cependant, les applications modernes – du traitement vidéo à l'analyse de grandes données – nécessitent l'exécution simultanée de plusieurs tâches. Sans concurrence, vous risquez de vous heurter à un "mur de performance", où même un serveur puissant reste inactif en attendant la fin des opérations d'entrée-sortie.
\nDans cet article, nous analyserons les techniques avancées de travail avec la concurrence en PHP : des appels système aux extensions de niveau noyau. Vous apprendrez comment faire fonctionner PHP en parallèle, sans perdre le contrôle des ressources.
\n\n1. Bases : processus vs threads en PHP
\nAvant de plonger dans le code, il est important de comprendre la différence entre les processus et les threads dans le contexte de PHP.
\n- \n
- Processus – des instances isolées, chacune avec sa propre mémoire. Créés via
pcntl_fork(). Adaptés aux tâches lourdes, mais nécessitent une communication interprocessus (IPC). \n - Threads – des "sous-tâches" légères au sein d'un même processus, partageant la mémoire. Implémentés via l'extension
pthreads. Idéaux pour travailler avec des données partagées, mais nécessitent une synchronisation. \n
Pour un niveau avancé, il est important de savoir combiner les deux approches. Par exemple, utiliser des forks pour isoler les tâches critiques, et des threads pour le traitement parallèle au sein d'un même contexte.
\n\n1.1 Processus parallèles via pcntl_fork()
\nL'appel système pcntl_fork() crée un processus fils qui copie la mémoire du parent. Voici un exemple de traitement parallèle de plusieurs URL :
<?php\n$urls = ['https://api.example.com/data1', 'https://api.example.com/data2', 'https://api.example.com/data3'];\n$pids = [];\n\nforeach ($urls as $url) {\n $pid = pcntl_fork();\n if ($pid == -1) {\n die('Impossible de créer le processus');\n } elseif ($pid) {\n // Processus parent : on sauvegarde le PID\n $pids[] = $pid;\n } else {\n // Processus fils : on exécute le téléchargement\n $data = file_get_contents($url);\n file_put_contents('/tmp/' . md5($url) . '.json', $data);\n exit(0); // On termine le processus fils\n }\n}\n\n// On attend la fin de tous les processus\nforeach ($pids as $pid) {\n pcntl_waitpid($pid, $status);\n}\necho "Toutes les URL ont été traitées en parallèle !";\n?>\nImportant : après fork(), les processus fils héritent de tous les descripteurs de fichiers ouverts et des connexions à la base de données. Fermez-les explicitement dans le processus fils pour éviter les conflits.
\n\n2. Tâches asynchrones avec ReactPHP et Amp
\nPour les applications web où la réactivité est importante, utilisez les bibliothèques de boucle événementielle. ReactPHP et Amp permettent d'effectuer des opérations non bloquantes, sans créer de processus séparés.
\n\n2.1 Exemple avec ReactPHP
\nInstallez la bibliothèque via Composer : composer require react/react. Ci-dessous, un client HTTP asynchrone qui envoie trois requêtes simultanément :
<?php\nrequire 'vendor/autoload.php';\n\nuse React\\EventLoop\\Factory;\nuse React\\HttpClient\\Client;\n\n$loop = Factory::create();\n$client = new Client($loop);\n\n$urls = ['http://example.com', 'http://example.org', 'http://example.net'];\n$promises = [];\n\nforeach ($urls as $url) {\n $request = $client->request('GET', $url);\n $request->on('response', function ($response) use ($url) {\n echo "Réponse de {$url} : " . $response->getCode() . PHP_EOL;\n });\n $request->end();\n}\n\n$loop->run();\n?>\nReactPHP crée une boucle d'événements unique qui traite toutes les requêtes sans blocage. C'est idéal pour les passerelles API ou les microservices où la rapidité de réponse est importante.
\n\n3. Gestion des threads avec pthreads (build ZTS)
\nL'extension pthreads est le seul moyen d'obtenir un véritable multithreading en PHP.
Blogs
Book Recommendations
Lire aussi
Rust : Fonctionnel ou POO ? Choisir le style pour un code idéal
Travailler avec WebAssembly et TypeScript : de A à Z — guide complet
La magie de `extern "C"` en C++ : accélération du code et compatibilité
Observabilité en C# : Traçage, Métriques et Logs en Pratique
Gestion des erreurs en Go : try/catch et au-delà — guide complet