Introduction : pourquoi PHP a besoin de la concurrence
PHP est traditionnellement considéré comme un langage synchrone, où chaque requête est traitée séquentiellement. Cependant, les applications web modernes nécessitent l'exécution de multiples tâches simultanément : traitement de files d'attente, travail avec des API, traitement d'images, analyse de données. La concurrence et le multithreading en PHP permettent de résoudre ces problèmes, améliorant les performances et la réactivité des applications.
Dans cet article, nous examinerons les principales approches : le multithreading via pthreads, les processus parallèles via pcntl_fork, la programmation asynchrone avec ReactPHP et les Fibers modernes en PHP 8.1+. Chaque méthode a ses forces et ses limites, que nous étudierons à l'aide d'exemples pratiques.
Approche 1 : Multithreading avec l'extension pthreads
pthreads est une extension pour travailler avec des threads en PHP. Elle est disponible uniquement pour la version CLI et nécessite une compilation avec le flag --enable-maintainer-zts. Les threads partagent la mémoire, ce qui permet un échange de données efficace, mais nécessite des précautions avec les verrous.
Installation et configuration
# Installation via peclpecl install pthreads
# Vérification dans php.iniextension=pthreads.soExemple : traitement parallèle d'un tableau
<?phpclass WorkerThread extends Thread { private $data; private $result;
public function __construct($data) { $this->data = $data; }
public function run() { // Simulation d'une opération lourde $this->result = array_map(function($item) { sleep(1); // 1 seconde par élément return $item * 2; }, $this->data); }
public function getResult() { return $this->result; }}
// Création de 5 threads$threads = [];$dataChunks = array_chunk(range(1, 100), 20);
foreach ($dataChunks as $chunk) { $thread = new WorkerThread($chunk); $thread->start(); $threads[] = $thread;}
// Collecte des résultats$finalResult = [];foreach ($threads as $thread) { $thread->join(); $finalResult = array_merge($finalResult, $thread->getResult());}
echo "Traitement de " . count($finalResult) . " éléments en ~5 secondes au lieu de 100.";Important : pthreads ne fonctionne pas dans un environnement web (Apache/Nginx + mod_php). Utilisez-le uniquement pour les scripts CLI, les workers et les démons.
Approche 2 : Processus parallèles via pcntl_fork
La fonction pcntl_fork() crée un processus enfant en copiant le script courant. Les processus sont isolés en mémoire, ce qui est plus sûr que les threads, mais la communication interprocessus (IPC) nécessite des mécanismes supplémentaires : files de messages, mémoire partagée ou sockets.
Exemple : chargement parallèle d'URL
<?php$urls = [ 'https://api.example.com/data1', 'https://api.example.com/data2', 'https://api.example.com/data3',];
$pids = [];foreach ($urls as $url) { $pid = pcntl_fork(); if ($pid == -1) { die("Erreur fork"); } elseif ($pid == 0) { // Processus enfant $content = file_get_contents($url); file_put_contents('/tmp/' . md5($url) . '.json', $content); exit(0); // Important de terminer le processus enfant } else { $pids[] = $pid; }}
// Attente de la fin de tous les processus enfantsforeach ($pids as $pid) { pcntl_waitpid($pid, $status);}
echo "Toutes les URL ont été chargées en parallèle.";Limites :
- Ne fonctionne pas avec un serveur web (CLI uniquement).
- Chaque processus consomme la mémoire du parent.
- Difficile de synchroniser l'accès aux ressources partagées.
Approche 3 : Asynchronisme avec ReactPHP
ReactPHP est une bibliothèque pour la programmation orientée événements