Cette bibliothèque fournit un petit wrapper simple autour de l'extension PCNTL de PHP. Il permet d'exécuter différents processus en parallèle, avec une API facile à utiliser.
Nous investissons beaucoup de ressources dans la création des meilleurs packages open source de leur catégorie. Vous pouvez nous soutenir en achetant l'un de nos produits payants.
Nous apprécions grandement que vous nous envoyiez une carte postale de votre ville natale, mentionnant le(s) forfait(s) que vous utilisez. Vous trouverez notre adresse sur notre page contact. Nous publions toutes les cartes postales reçues sur notre mur virtuel de cartes postales.
Vous pouvez installer le package via composer :
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 ();
Lors de la création de processus asynchrones, une instance de ParallelProcess
vous sera renvoyée. Vous pouvez ajouter les hooks d’événement suivants sur un processus.
$ 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.
})
;
Au lieu d'utiliser des méthodes sur l'objet $pool
, vous pouvez également utiliser les fonctions d'assistance async
et 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 une Exception
ou Error
est générée depuis un processus enfant, elle peut être interceptée par processus en spécifiant un rappel dans la méthode ->catch()
.
$ pool
-> add ( function () {
/ / ...
})
-> catch ( function ( $ exception ) {
/ / Handle the thrown exception for this child process.
})
;
Si aucun gestionnaire d'erreur n'est ajouté, l'erreur sera générée dans le processus parent lors de l'appel de await()
ou $pool->wait()
.
Si le processus enfant s'arrête de manière inattendue sans lancer un Throwable
, la sortie écrite dans stderr
sera encapsulée et lancée comme SpatieAsyncParallelError
dans le processus parent.
En faisant allusion aux fonctions catch
, vous pouvez fournir plusieurs gestionnaires d'erreurs, chacun pour des types d'erreurs individuels.
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / Handle `MyException`
})
-> catch ( function ( OtherException $ e ) {
/ / Handle `OtherException`
});
Notez que dès qu'une exception est gérée, elle ne déclenchera aucun autre gestionnaire
$ 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 vous devez arrêter un pool plus tôt, car la tâche qu'il effectuait a été terminée par l'un des processus enfants, vous pouvez utiliser la méthode $pool->stop()
. Cela empêchera le pool de démarrer des processus supplémentaires.
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 ();
Notez qu'un pool deviendra inutile après avoir été arrêté et qu'un nouveau pool devra être créé si nécessaire.
Par défaut, le pool utilisera php
pour exécuter ses processus enfants. Vous pouvez configurer un autre binaire comme ceci :
Pool:: create ()
-> withBinary ( ' /path/to/php ' );
En plus d'utiliser des fermetures, vous pouvez également travailler avec un Task
. Une Task
est utile dans les situations où vous avez besoin de plus de travail de configuration dans le processus enfant. Étant donné qu'un processus enfant est toujours démarré à partir de rien, il est probable que vous souhaitiez l'initialiser, par exemple. le conteneur de dépendances avant d’exécuter la tâche. La classe Task
facilite cette tâche.
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 vous souhaitez encapsuler la logique de votre tâche, mais ne souhaitez pas créer un objet Task
à part entière, vous pouvez également transmettre un objet invocable au Pool
.
class InvokableClass
{
/ / ...
public function __invoke ()
{
/ / ...
}
}
$ pool -> add ( new InvokableClass ( / * ... * / ));
Vous êtes libre de créer autant de pools que vous le souhaitez, chaque pool possède sa propre file d'attente de processus qu'il va gérer.
Un pool est configurable par le développeur :
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 les extensions requises ( pcntl
et posix
) ne sont pas installées dans votre runtime PHP actuel, le Pool
reviendra automatiquement à l'exécution synchrone des tâches.
La classe Pool
possède une méthode statique isSupported
que vous pouvez appeler pour vérifier si votre plate-forme est capable d'exécuter des processus asynchrones.
Si vous utilisez une Task
pour exécuter des processus, seule la méthode run
de ces tâches sera appelée lors de l'exécution en mode synchrone.
Lorsque vous utilisez ce package, vous vous demandez probablement ce qui se passe sous la surface.
Nous utilisons le composant symfony/process
pour créer et gérer des processus enfants en PHP. En créant des processus enfants à la volée, nous sommes capables d'exécuter des scripts PHP en parallèle. Ce parallélisme peut améliorer considérablement les performances lors du traitement de plusieurs tâches synchrones, qui n'ont pas vraiment besoin de s'attendre. En attribuant à ces tâches un processus distinct sur lequel s'exécuter, le système d'exploitation sous-jacent peut se charger de les exécuter en parallèle.
Il y a une mise en garde lors de la génération dynamique de processus : vous devez vous assurer qu'il n'y aura pas trop de processus à la fois, sinon l'application pourrait planter. La classe Pool
fournie par ce package se charge de gérer autant de processus que vous le souhaitez en les planifiant et en les exécutant lorsque cela est possible.
C'est la partie que fait async()
ou $pool->add()
. Voyons maintenant ce que fait await()
ou $pool->wait()
.
Lorsque plusieurs processus sont générés, chacun peut avoir un délai d’exécution différent. Un processus pourrait par exemple. doit attendre un appel HTTP, tandis que l'autre doit traiter de grandes quantités de données. Parfois, vous avez également des points dans votre code qui doivent attendre que le résultat d'un processus soit renvoyé.
C'est pourquoi nous devons attendre à un certain moment : que tous les processus d'un pool se terminent, afin que nous puissions être sûrs qu'il est possible de continuer en toute sécurité sans tuer accidentellement les processus enfants qui ne sont pas encore terminés.
L'attente de tous les processus se fait à l'aide d'une boucle while
, qui attendra que tous les processus soient terminés. La détermination du moment où un processus est terminé se fait en utilisant un écouteur sur le signal SIGCHLD
. Ce signal est émis lorsqu'un processus enfant est terminé par le noyau du système d'exploitation. Depuis PHP 7.1, il existe une bien meilleure prise en charge de l'écoute et de la gestion des signaux, ce qui rend cette approche plus performante que par exemple. en utilisant des forks ou des sockets de processus pour la communication. Vous pouvez en savoir plus ici.
Lorsqu'un processus est terminé, son événement de réussite est déclenché, auquel vous pouvez vous connecter avec la fonction ->then()
. De même, lorsqu'un processus échoue ou expire, la boucle mettra à jour l'état de ce processus et passera à autre chose. Lorsque tous les processus sont terminés, la boucle while verra qu'il n'y a plus rien à attendre et s'arrêtera. C'est le moment où votre processus parent peut continuer à s'exécuter.
Nous avons rédigé un article de blog contenant plus d'informations sur les cas d'utilisation de ce package, ainsi que des comparaisons avec d'autres bibliothèques PHP asynchrones comme ReactPHP et Amp : http://stitcher.io/blog/asynchronous-php.
composer test
Veuillez consulter CHANGELOG pour plus d'informations sur ce qui a changé récemment.
Veuillez consulter CONTRIBUER pour plus de détails.
Si vous avez trouvé un bug concernant la sécurité, veuillez envoyer un mail à [email protected] au lieu d'utiliser le suivi des problèmes.
Vous êtes libre d'utiliser ce package, mais s'il parvient à votre environnement de production, nous apprécions grandement que vous nous envoyiez une carte postale de votre ville natale, mentionnant lequel de nos packages vous utilisez.
Notre adresse est : Spatie, Kruikstraat 22, 2018 Anvers, Belgique.
Nous publions toutes les cartes postales reçues sur le site Internet de notre entreprise.
La licence MIT (MIT). Veuillez consulter le fichier de licence pour plus d'informations.