Introducción: por qué PHP necesita concurrencia
Tradicionalmente, PHP se considera un lenguaje síncrono donde cada solicitud se procesa secuencialmente. Sin embargo, las aplicaciones web modernas requieren ejecutar múltiples tareas simultáneamente: procesamiento de colas, trabajo con APIs, procesamiento de imágenes, análisis de datos. La concurrencia y el multiprocesamiento en PHP permiten resolver estas tareas, mejorando el rendimiento y la capacidad de respuesta de las aplicaciones.
En este artículo analizaremos los enfoques principales: multiprocesamiento con pthreads, procesos paralelos con pcntl_fork, programación asíncrona con ReactPHP y los modernos Fibers en PHP 8.1+. Cada método tiene sus fortalezas y limitaciones, que revisaremos con ejemplos prácticos.
Enfoque 1: Multiprocesamiento con la extensión pthreads
pthreads es una extensión para trabajar con hilos (threads) en PHP. Solo está disponible para la versión CLI y requiere compilación con la bandera --enable-maintainer-zts. Los hilos comparten memoria, lo que permite intercambiar datos de manera eficiente, pero requiere cuidado con los bloqueos.
Instalación y configuración
# Instalación a través de peclpecl install pthreads
# Verificación en php.iniextension=pthreads.soEjemplo: procesamiento paralelo de un array
<?phpclass WorkerThread extends Thread { private $data; private $result;
public function __construct($data) { $this->data = $data; }
public function run() { // Simulación de una operación pesada $this->result = array_map(function($item) { sleep(1); // 1 segundo por elemento return $item * 2; }, $this->data); }
public function getResult() { return $this->result; }}
// Creamos 5 hilos$threads = [];$dataChunks = array_chunk(range(1, 100), 20);
foreach ($dataChunks as $chunk) { $thread = new WorkerThread($chunk); $thread->start(); $threads[] = $thread;}
// Recolección de resultados$finalResult = [];foreach ($threads as $thread) { $thread->join(); $finalResult = array_merge($finalResult, $thread->getResult());}
echo "Procesados " . count($finalResult) . " elementos en ~5 segundos en lugar de 100.";Importante: pthreads no funciona en entornos web (Apache/Nginx + mod_php). Úselo solo para scripts CLI, workers y demonios.
Enfoque 2: Procesos paralelos con pcntl_fork
La función pcntl_fork() crea un proceso hijo, copiando el script actual. Los procesos están aislados en memoria, lo que es más seguro que los hilos, pero la comunicación entre procesos (IPC) requiere mecanismos adicionales: colas de mensajes, memoria compartida o sockets.
Ejemplo: descarga paralela de URLs
<?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("Error en fork"); } elseif ($pid == 0) { // Proceso hijo $content = file_get_contents($url); file_put_contents('/tmp/' . md5($url) . '.json', $content); exit(0); // Importante finalizar el proceso hijo } else { $pids[] = $pid; }}
// Esperar la finalización de todos los procesos hijosforeach ($pids as $pid) { pcntl_waitpid($pid, $status);}
echo "Todas las URLs se descargaron en paralelo.";Limitaciones:
- No funciona con servidores web (solo CLI).
- Cada proceso consume la memoria del padre.
- Es difícil sincronizar el acceso a recursos compartidos.
Enfoque 3: Asincronía con ReactPHP
ReactPHP es una biblioteca para programación orientada a eventos