Introducción a la concurrencia y el multiproceso en PHP
Tradicionalmente, PHP se considera un lenguaje síncrono y de un solo hilo. Sin embargo, las aplicaciones web modernas requieren procesar múltiples tareas simultáneamente: carga de archivos, trabajo con APIs, procesamiento de colas. La concurrencia y el multiproceso en PHP permiten resolver estas tareas, acelerando la ejecución de scripts y mejorando la capacidad de respuesta de las aplicaciones.
En este artículo analizaremos los conceptos clave: desde los principios básicos de concurrencia hasta la aplicación práctica de las extensiones pthreads y parallel. Aprenderá cómo organizar la ejecución paralela de tareas, evitar condiciones de carrera y mejorar el rendimiento de su código PHP.
Conceptos principales de concurrencia y multiproceso
Sincronía vs Asincronía
En el modelo síncrono, PHP ejecuta el código estrictamente de forma secuencial. Si un script realiza una solicitud HTTP, la ejecución se detiene hasta recibir la respuesta. La asincronía permite iniciar tareas sin esperar a que finalicen.
Ejemplo de código síncrono:
<?php$result1 = file_get_contents('https://api.example.com/data1');$result2 = file_get_contents('https://api.example.com/data2');// Ambas solicitudes se ejecutan secuencialmente?>Hilos y procesos
- Proceso — copia aislada de un programa con su propio espacio de direcciones.
- Hilo — unidad de ejecución ligera dentro de un proceso, que comparte memoria.
En PHP, el multiproceso se implementa mediante hilos (threads). Para trabajar con ellos se requieren extensiones especiales, ya que la compilación estándar de PHP no admite hilos.
Condición de carrera y sincronización
Cuando varios hilos trabajan con datos compartidos, puede ocurrir una condición de carrera (race condition). Para evitarla se utilizan mutex, bloqueos y operaciones atómicas.
Herramientas para multiproceso en PHP
Extensión pthreads
pthreads — una de las primeras extensiones para trabajar con hilos. Proporciona las clases Thread, Worker y Pool. Importante: la extensión solo funciona en modo CLI y requiere una compilación de PHP con ZTS (Zend Thread Safety).
Ejemplo de un hilo simple:
<?phpclass MyThread extends Thread { public function run() { echo "Hilo iniciado"; }}$thread = new MyThread();$thread->start();$thread->join();?>Extensión parallel
parallel — una extensión más moderna, aparecida en PHP 7.4. Es más conveniente y segura. Funciona mediante canales (channels) para transferir datos entre hilos.
Ejemplo con parallel:
<?php$runtime = new \\parallel\\Runtime();$future = $runtime->run(function(){ return "¡Hola desde un hilo paralelo!";});echo $future->value(); // Obtenemos el resultado?>Asincronía con ReactPHP y Amp
Si no necesita multiproceso real, pero requiere concurrencia, utilice bibliotecas de entrada/salida asíncrona:
- ReactPHP — biblioteca orientada a eventos con event loop.
- Amp — async/await para PHP, similar a JavaScript.
Ejemplos prácticos y mejores prácticas
Ejemplo: Procesamiento paralelo de URLs
Supongamos que necesita verificar la disponibilidad de 10 sitios web. De forma síncrona, esto tomaría mucho tiempo. Usamos parallel para acelerarlo:
<?php$urls = [ 'https://google.com', 'https://yandex.ru', 'https://github.com'];
$runtimes = [];$futures = [];
foreach ($urls as $url) { $runtime = new \\parallel\\Runtime(); $runtimes[] = $runtime; $futures[] = $runtime->run(function($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5);