Esta biblioteca proporciona un contenedor pequeño y sencillo para la extensión PCNTL de PHP. Permite ejecutar diferentes procesos en paralelo, con una API fácil de usar.
Invertimos muchos recursos en la creación de los mejores paquetes de código abierto. Puedes apoyarnos comprando uno de nuestros productos pagos.
Agradecemos mucho que nos envíe una postal desde su ciudad natal, mencionando cuál de nuestros paquetes está utilizando. Encontrarás nuestra dirección en nuestra página de contacto. Publicamos todas las postales recibidas en nuestro muro virtual de postales.
Puede instalar el paquete a través del compositor:
composer require spatie/async
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( $ things as $ thing ) {
$ pool -> add ( function () use ( $ thing ) {
/ / Do a thing
})-> then ( function ( $ output ) {
/ / Handle success
})-> catch ( function ( Throwable $ exception ) {
/ / Handle exception
});
}
$ pool -> wait ();
Al crear procesos asincrónicos, obtendrá una instancia de ParallelProcess
. Puede agregar los siguientes enlaces de eventos en un proceso.
$ pool
-> add ( function () {
/ / ...
})
-> then ( function ( $ output ) {
/ / On success , `$output` is returned by the process or callable you passed to the queue .
})
-> catch ( function ( $ exception ) {
/ / When an exception is thrown from within a process , it 's caught and passed here.
})
-> timeout ( function () {
/ / A process took too long to finish.
})
;
En lugar de utilizar métodos en el objeto $pool
, también puede utilizar las funciones auxiliares async
y await
.
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( range ( 1 , 5 ) as $ i ) {
$ pool [] = async ( function () {
usleep ( random_int ( 10 , 1000 ));
return 2 ;
})-> then ( function ( int $ output ) {
$ this -> counter += $ output ;
});
}
await ( $ pool );
Si se genera una Exception
o Error
desde un proceso secundario, se puede detectar por proceso especificando una devolución de llamada en el método ->catch()
.
$ pool
-> add ( function () {
/ / ...
})
-> catch ( function ( $ exception ) {
/ / Handle the thrown exception for this child process.
})
;
Si no se agrega ningún controlador de errores, el error se generará en el proceso principal al llamar await()
o $pool->wait()
.
Si el proceso secundario se detiene inesperadamente sin generar un Throwable
, la salida escrita en stderr
se empaquetará y se generará como SpatieAsyncParallelError
en el proceso principal.
Al escribir sugerencias en las funciones catch
, puede proporcionar múltiples controladores de errores, cada uno para tipos individuales de errores.
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / Handle `MyException`
})
-> catch ( function ( OtherException $ e ) {
/ / Handle `OtherException`
});
Tenga en cuenta que tan pronto como se maneja una excepción, no activará ningún otro controlador.
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / This one is triggerd when `MyException` is thrown
})
-> catch ( function ( Exception $ e ) {
/ / This one is not triggerd , even though `M yException ` extends `E xception `
});
Si necesita detener un grupo antes de tiempo, porque la tarea que estaba realizando ha sido completada por uno de los procesos secundarios, puede utilizar el método $pool->stop()
. Esto evitará que el grupo inicie procesos adicionales.
use Spatie Async Pool ;
$ pool = Pool:: create ();
/ / Generate 10 k processes generating random numbers
for ( $ i = 0 ; $ i < 10000 ; $ i ++) {
$ pool -> add ( function () use ( $ i ) {
return rand ( 0 , 100 );
})-> then ( function ( $ output ) use ( $ pool ) {
/ / If one of them randomly picks 100 , end the pool early .
if ( $ output === 100 ) {
$ pool -> stop ();
}
});
}
$ pool -> wait ();
Tenga en cuenta que un grupo quedará inútil después de detenerlo y se debe crear un nuevo grupo si es necesario.
De forma predeterminada, el grupo utilizará php
para ejecutar sus procesos secundarios. Puedes configurar otro binario así:
Pool:: create ()
-> withBinary ( ' /path/to/php ' );
Además de usar cierres, también puedes trabajar con una Task
. Una Task
es útil en situaciones en las que necesita más trabajo de configuración en el proceso hijo. Debido a que un proceso hijo siempre se inicia desde la nada, es probable que desee inicializarlo, por ejemplo. el contenedor de dependencia antes de ejecutar la tarea. La clase Task
hace que esto sea más fácil de hacer.
use Spatie Async Task ;
class MyTask extends Task
{
public function configure ()
{
/ / Setup eg . dependency container , load config , ...
}
public function run ()
{
/ / Do the real work here.
}
}
/ / Add the task to the pool
$ pool -> add ( new MyTask ());
Si desea encapsular la lógica de su tarea, pero no desea crear un objeto Task
completo, también puede pasar un objeto invocable al Pool
.
class InvokableClass
{
/ / ...
public function __invoke ()
{
/ / ...
}
}
$ pool -> add ( new InvokableClass ( / * ... * / ));
Eres libre de crear tantos grupos como quieras, cada grupo tiene su propia cola de procesos que manejará.
El desarrollador puede configurar un grupo:
use Spatie Async Pool ;
$ pool = Pool:: create ()
/ / The maximum amount of processes which can run simultaneously.
-> concurrency ( 20 )
/ / The maximum amount of time a process may take to finish in seconds
/ / ( decimal places are supported for more granular timeouts ) .
-> timeout ( 15 )
/ / Configure which autoloader sub processes should use.
-> autoload ( __DIR__ . ' /../../vendor/autoload.php ' )
/ / Configure how long the loop should sleep before re - checking the process statuses in microseconds .
-> sleepTime ( 50000 )
;
Si las extensiones requeridas ( pcntl
y posix
) no están instaladas en su tiempo de ejecución PHP actual, el Pool
recurrirá automáticamente a la ejecución sincrónica de tareas.
La clase Pool
tiene un método estático isSupported
al que puede llamar para comprobar si su plataforma puede ejecutar procesos asincrónicos.
Si está utilizando una Task
para ejecutar procesos, solo se llamará al método run
de esas tareas cuando se ejecuten en modo sincrónico.
Al utilizar este paquete, probablemente se esté preguntando qué sucede debajo de la superficie.
Estamos usando el componente symfony/process
para crear y administrar procesos secundarios en PHP. Al crear procesos secundarios sobre la marcha, podemos ejecutar scripts PHP en paralelo. Este paralelismo puede mejorar significativamente el rendimiento cuando se trata de múltiples tareas sincrónicas, que en realidad no necesitan esperarse unas a otras. Al darle a estas tareas un proceso separado para ejecutar, el sistema operativo subyacente puede encargarse de ejecutarlas en paralelo.
Hay una advertencia al generar procesos dinámicamente: debe asegurarse de que no habrá demasiados procesos a la vez, o la aplicación podría fallar. La clase Pool
proporcionada por este paquete se encarga de manejar tantos procesos como desee programándolos y ejecutándolos cuando sea posible.
Esa es la parte que hace async()
o $pool->add()
. Ahora veamos qué hace await()
o $pool->wait()
.
Cuando se generan varios procesos, cada uno puede tener un tiempo de finalización distinto. Un proceso podría, por ejemplo. tiene que esperar una llamada HTTP, mientras que el otro tiene que procesar grandes cantidades de datos. A veces también tienes puntos en tu código que tienen que esperar hasta que se devuelva el resultado de un proceso.
Es por eso que tenemos que esperar en un momento determinado: a que finalicen todos los procesos en un grupo, para que podamos estar seguros de que es seguro continuar sin matar accidentalmente los procesos secundarios que aún no han finalizado.
La espera de todos los procesos se realiza mediante un bucle while
, que esperará hasta que finalicen todos los procesos. La determinación de cuándo finaliza un proceso se realiza mediante el uso de un oyente en la señal SIGCHLD
. Esta señal se emite cuando el kernel del sistema operativo finaliza un proceso secundario. A partir de PHP 7.1, hay un soporte mucho mejor para escuchar y manejar señales, lo que hace que este enfoque sea más eficaz que, por ejemplo. utilizando bifurcaciones o enchufes de proceso para la comunicación. Puedes leer más sobre esto aquí.
Cuando finaliza un proceso, se activa su evento de éxito, al que puede conectarse con la función ->then()
. Del mismo modo, cuando un proceso falla o se agota el tiempo de espera, el bucle actualizará el estado de ese proceso y seguirá adelante. Cuando finalicen todos los procesos, el ciclo while verá que no hay nada más que esperar y se detendrá. Este es el momento en que su proceso principal puede continuar ejecutándose.
Hemos escrito una publicación de blog que contiene más información sobre los casos de uso de este paquete, además de hacer comparaciones con otras bibliotecas PHP asincrónicas como ReactPHP y Amp: http://stitcher.io/blog/asynchronous-php.
composer test
Consulte CHANGELOG para obtener más información sobre los cambios recientes.
Consulte CONTRIBUCIÓN para obtener más detalles.
Si encuentra un error relacionado con la seguridad, envíe un correo electrónico a [email protected] en lugar de utilizar el rastreador de problemas.
Eres libre de utilizar este paquete, pero si llega a tu entorno de producción, te agradeceremos mucho que nos envíes una postal desde tu ciudad natal, mencionando cuál de nuestros paquetes estás utilizando.
Nuestra dirección es: Spatie, Kruikstraat 22, 2018 Amberes, Bélgica.
Publicamos todas las postales recibidas en el sitio web de nuestra empresa.
La Licencia MIT (MIT). Consulte el archivo de licencia para obtener más información.