Introducción: por qué la concurrencia en PHP no es un mito
\nTradicionalmente, PHP se considera un lenguaje síncrono donde cada solicitud se procesa secuencialmente. Sin embargo, las aplicaciones modernas —desde el procesamiento de video hasta el análisis de grandes datos— requieren la ejecución de múltiples tareas simultáneamente. Sin concurrencia, corre el riesgo de chocar contra el "muro de rendimiento", donde incluso un servidor potente permanece inactivo esperando que se completen las operaciones de entrada/salida.
\nEn este artículo, analizaremos técnicas avanzadas para trabajar con concurrencia en PHP: desde llamadas al sistema hasta extensiones a nivel de kernel. Aprenderá cómo hacer que PHP funcione en paralelo sin perder el control sobre los recursos.
\n\n1. Fundamentos: procesos vs hilos en PHP
\nAntes de sumergirnos en el código, es importante entender la diferencia entre procesos e hilos en el contexto de PHP.
\n- \n
- Procesos — instancias aisladas, cada una con su propia memoria. Se crean mediante
pcntl_fork(). Son adecuados para tareas pesadas, pero requieren comunicación entre procesos (IPC). \n - Hilos — "subtareas" ligeras dentro de un mismo proceso que comparten memoria. Se implementan mediante la extensión
pthreads. Son ideales para trabajar con datos compartidos, pero requieren sincronización. \n
Para un nivel avanzado, es importante saber combinar ambos enfoques. Por ejemplo, usar forks para aislar tareas críticas y hilos para el procesamiento paralelo dentro de un mismo contexto.
\n\n1.1 Procesos paralelos mediante pcntl_fork()
\nLa llamada al sistema pcntl_fork() crea un proceso hijo que copia la memoria del padre. Veamos un ejemplo de procesamiento paralelo de varias 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('No se pudo crear el proceso');\n } elseif ($pid) {\n // Proceso padre: guardamos el PID\n $pids[] = $pid;\n } else {\n // Proceso hijo: realizamos la descarga\n $data = file_get_contents($url);\n file_put_contents('/tmp/' . md5($url) . '.json', $data);\n exit(0); // Finalizamos el proceso hijo\n }\n}\n\n// Esperamos a que todos los procesos terminen\nforeach ($pids as $pid) {\n pcntl_waitpid($pid, $status);\n}\necho "¡Todas las URL se procesaron en paralelo!";\n?>\nImportante: después de fork(), los procesos hijos heredan todos los descriptores de archivo y conexiones a la base de datos abiertos. Ciérrelos explícitamente en el proceso hijo para evitar conflictos.
\n\n2. Tareas asíncronas con ReactPHP y Amp
\nPara aplicaciones web donde la reactividad es importante, utilice bibliotecas de bucle orientado a eventos. ReactPHP y Amp permiten realizar operaciones no bloqueantes sin crear procesos separados.
\n\n2.1 Ejemplo con ReactPHP
\nInstale la biblioteca mediante Composer: composer require react/react. A continuación, un cliente HTTP asíncrono que envía tres solicitudes simultáneamente:
<?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 "Respuesta de {$url}: " . $response->getCode() . PHP_EOL;\n });\n $request->end();\n}\n\n$loop->run();\n?>\nReactPHP crea un único bucle de eventos que procesa todas las solicitudes sin bloqueo. Esto es ideal para puertas de enlace API o microservicios donde la velocidad de respuesta es importante.
\n\n3. Gestión de hilos con pthreads (compilación ZTS)
\nLa extensión pthreads es la única forma de obtener verdadero multihilo en PHP.
Blogs
Book Recommendations
Leer también
Contenerización de aplicaciones C++ con Docker: guía paso a paso
Las mejores IDE y herramientas para desarrollo Swift en 2025
Programación funcional en PHP: desde los fundamentos hasta la práctica
Generics en C++: para qué sirven y cómo usar plantillas
«React refers to a UMD global»: cómo TypeScript se vuelve loco