Introduction à Flow
le 20 septembre 2024
La présentation liée à l'article :
Connaissez-vous ?
- Nodered
- Apache Airflow
- Google Blockly
- Huginn
- IFTTT
- Zapier
- Make
- Workato
- n8n.io
- Kestra
- Raccourci
- Uniflow
- Symfony Messenger
Tout cela relève de la programmation visuelle ou de l'orchestration de données
Qu'est-ce que Flow ?
Il s'agit d'un framework d'orchestration visuelle de données en PHP
Flow est un framework d'orchestration visuelle de données de pointe conçu spécifiquement pour PHP. Il offre aux développeurs un moyen de créer des flux de travail complexes à l'aide d'une interface visuelle, permettant l'orchestration des données et des processus de manière plus intuitive et évolutive. Flow vous permet de gérer les transformations de données, d'intégrer divers services et de définir des processus asynchrones en toute simplicité, ce qui en fait un outil essentiel pour la création d'applications PHP modernes.
Quel est l'objectif de Flow ?
Flow cherche à simplifier la manière dont les développeurs créent et gèrent leurs applications PHP en se concentrant sur trois principes fondamentaux
-
Adopter l'asynchrone comme implémentation native : Flow adopte la programmation asynchrone dès le départ, vous permettant de créer des applications hautement performantes capables de gérer efficacement les tâches simultanées.
-
Construisez votre code avec la programmation fonctionnelle : Flow encourage une approche de programmation fonctionnelle, qui favorise l'immuabilité et la création de fonctions pures, rendant votre code plus prévisible, modulaire et plus facile à tester.
-
Assemblez votre code visuellement : avec Flow, vous pouvez composer et organiser visuellement les différents composants de votre application. Cela permet de voir facilement comment les différents processus interagissent, ce qui vous aide à concevoir et à gérer des flux de travail complexes de manière plus intuitive.
Programmation basée sur les flux
La programmation basée sur les flux (FBP) est un paradigme de programmation introduit par J. Paul Rodker Morrison dans les années 1960. Il a ensuite été implémenté dans divers langages (JavaScript, PHP, C) par Henri Bergius. L'idée principale de FBP est de représenter un modèle d'application sous la forme d'un graphe de processus indépendants où les données sont échangées via des connexions. L'objectif est d'exprimer un problème en termes de transformations de flux de données.
Par exemple, imaginez une usine d'embouteillage. Une bouteille vide passe d'abord par une étape de remplissage. Une fois cette opération terminée, la bouteille passe à une étape de scellage pour fermer son contenu en toute sécurité. Enfin, la bouteille est étiquetée lors de la dernière étape, ce qui la rend prête à être distribuée.
Dans FBP, il existe deux perspectives pour visualiser un tel système. La première est l'approche de bas niveau, appelée logique métier, où nous nous concentrons sur chaque composant (ou processus) individuellement. Chaque composant possède une ou plusieurs entrées et sorties. Le rôle de chaque composant est de traiter les données entrantes (entrée) et de renvoyer les résultats via la sortie. Chaque composant peut être implémenté dans n'importe quel langage de programmation.
La deuxième perspective est l'approche de haut niveau, appelée logique de communication. Dans cette approche, le flux de données est représenté en connectant les composants via les connexions du graphique. Le même composant peut être réutilisé dans différentes parties du graphique. Les données qui circulent dans un tel graphique sont appelées paquets d'informations (IP). De plus, un tel graphique peut être considéré comme une grande boîte noire avec ses propres entrées et sorties, ce qui permet de créer des systèmes cohérents et évolutifs en construisant de nouveaux graphiques à partir de graphiques existants.
Avantages de FBP :
- Parallélisme naturel : si un composant est surchargé de données, vous pouvez simplement le dupliquer (le mettre à l'échelle) pour augmenter la capacité de traitement. C'est ce qu'on appelle la contre-pression, où trop de paquets d'informations submergent un composant.
- Tests unitaires : chaque composant peut facilement être testé unitairement pour son processus spécifique.
- Pas de mémoire partagée ni de verrous : les composants étant indépendants, il n'y a aucun problème de mémoire partagée ou de verrous.
- Représentation visuelle : la création d'un graphique de données est simple à représenter visuellement, ce qui conduit à une programmation visuelle ou même à des solutions sans code.
Programmation basée sur le flux en rail de données
Basée sur le travail d'Anton Mishchuk, la programmation orientée chemin de fer (ROP) est un modèle de conception axé sur la gestion des erreurs de manière fonctionnelle. Expliquons le concept avec un exemple. Imaginez un processus composé de plusieurs étapes : récupérer une demande d'utilisateur, valider les données, mettre à jour la base de données utilisateur, envoyer un e-mail de vérification et renvoyer le résultat à l'utilisateur.
Dans la programmation orientée objet classique, vous pouvez écrire une seule fonction pour gérer cette tâche. Mais que se passe-t-il si les données ne sont pas valides ? Vous ajoutez une condition pour gérer ce cas. Que se passe-t-il s'il y a un problème de connexion à la base de données ? Vous encapsulez le code dans un bloc « try-catch ». Que se passe-t-il si l'utilisateur n'existe pas dans la base de données ? Vous ajoutez plus de logique pour le gérer. L'e-mail de vérification a-t-il été envoyé avec succès ?ly ? Vous introduisez la journalisation pour cela. Au fil du temps, un processus simple peut devenir complexe et difficile à maintenir à mesure que de nouvelles exigences apparaissent.
La programmation orientée chemin de fer offre un moyen fonctionnel de gérer les erreurs. L'idée est de construire votre programme sur une série de « rails ». Chaque rail comporte deux parties : la partie fonctionnelle, qui traite les données, et la partie de gestion des erreurs. Vous pouvez composer votre programme en enchaînant ces rails. Le processus s'exécute comme prévu et si une erreur se produit, elle est immédiatement envoyée à la fin de la chaîne. Cette approche vous permet de composer un programme à partir de rails indépendants qui peuvent être testés individuellement.
La programmation basée sur le flux ferroviaire combine les deux concepts (FBP et ROP) en un seul système cohérent. Définissons cela étape par étape.
Considérez un ensemble simple d'opérations comme AddOne
, MultByTwo
et MinusThree
. Ces opérations sont connectées par des rails. À une extrémité, vous avez un producteur, un processus responsable de la génération des données. Vous concaténez ces opérations sur les rails, ajoutez un système d'erreurs pour la gestion des erreurs et, à l'autre extrémité, un consommateur qui traite la sortie finale. Un superviseur gère l'ensemble du système, instancie et orchestrait tous les composants.
Comment cela fonctionne-t-il ? Comme dans FBP, un client envoie un paquet d'informations au producteur. Ce paquet circule dans les rails, est traité et transformé par chaque opération, et finalement renvoyé au client par le consommateur.
Ce qui est intéressant, c'est que plusieurs clients peuvent envoyer des requêtes simultanément. Chaque client envoie un ou plusieurs paquets d'informations dans le réseau, et le système traite et renvoie les résultats.
Dans un cas d'utilisation plus avancé, imaginez que l'opération « MultByTwo » nécessite beaucoup de ressources. Si plusieurs clients envoient trop de paquets d'informations, nous rencontrons une contre-pression. Cela se produit lorsque l'opération « MultByTwo » est submergée par trop de données à traiter, ce qui provoque le blocage du flux d'informations. Pour gérer cela, nous pouvons faire évoluer l'opération en augmentant le nombre d'instances « MultByTwo », ce qui évite les goulots d'étranglement et assure un traitement plus fluide. Le système de gestion des erreurs peut également être rendu évolutif de manière similaire.
Avantages de la programmation basée sur le flux ferroviaire :
- La structure des données dans le paquet d'informations est explicite et bien définie.
- Il est facile de suivre où se trouve le paquet d'informations dans le pipeline de traitement.
- Le système est intrinsèquement parallélisé et simple à configurer.
- Le programme est facile à entretenir et à réutiliser, car chaque rail du système est traité comme un composant indépendant et réutilisable.
Utiliser Y-Combinator
Y-Combinator offre un moyen d'introduire la récursivité dans un langage qui ne la prend pas en charge nativement. Alors pourquoi envisager cela alors que nous avons déjà la récursivité en PHP ? La clé réside dans la nature fonctionnelle et itérative de la récursivité, comme le démontre un exemple classique : la fonction factorielle.
Dans un pipeline simple codé en PHP, la récursivité est absente. Dans un flux simple, l'exécution se déplace de haut en bas sans possibilité de reculer par récursivité. C'est l'élément manquant qui nous permet d'écrire des programmes plus complexes.
Qu'est-ce que le calcul lambda ?
Avant de discuter du combinateur Y, nous devons introduire le calcul lambda, qui constitue la base de la récursivité dans la programmation fonctionnelle. Développé par Alonzo Church à l'Université de Princeton, le calcul lambda fournit un cadre théorique pour comprendre les fonctions et leurs calculs.
Il est intéressant de noter que Church était le mentor d'Alan Turing, qui a inventé la machine de Turing, un autre modèle fondamental de calcul. La machine de Turing et le calcul lambda sont tous deux des modèles équivalents, comme le décrit la thèse de Church-Turing.
Dans le calcul lambda, une fonction est traitée comme une boîte noire : elle prend des entrées et produit des sorties. Par exemple, si nous entrons « X », la boîte noire produit « X + 1 ». Ce comportement est représenté par la notation lambda : « λ x . x + 1, ce qui signifie que pour une entrée
X, la fonction renvoie
X + 1`.
Le calcul lambda introduit également le concept de fonctions pures, c'est-à-dire des fonctions qui renvoient toujours la même sortie pour les mêmes entrées sans aucun état interne.
Application du calcul lambda à la récursivité
En programmation fonctionnelle, la récursivité peut être introduite même dans les langages qui ne la prennent pas en charge nativement. Le Y-Combinator y parvient en appliquant une fonction à lui-même. Ce concept d'auto-application permet un comportement récursif même lorsque les mécanismes de récursivité traditionnels sont absents.
Par exemple, une fonction factorielle récursive en calcul lambda ressemblerait à ceci :
-
fac(3) = 3 * fac(2) = 3 * 2 * fac(1) = 3 * 2 * 1 = 6
Mais comment définissons-nous la récursivité en calcul lambda ? Le Y-Combinator nous permet d'exprimer la récursivité dans n'importe quel langage fonctionnel, même lorsque le langage ne fournit pas de moyen direct d'effectuer des appels récursifs.
Y-Combinator en PHP
En PHP, nous pouvons implémenter le Y-Combinator en utilisant le code suivant :
$Y = fn(Closure $f) => $U(fn(Closure $x) => $f(fn(Closure $y) => $U($x)($y)));
Ce n'est qu'une des nombreuses implémentations possibles en PHP. Une autre implémentation élégante peut être trouvée dans le référentiel loophp, qui couvre également d'autres concepts de calcul lambda. Pour plus de détails, je vous recommande de consulter le référentiel : loophp/combinator.
De plus, le référentiel d'Igor W. fournit une implémentation de calcul lambda en PHP, vous permettant d'écrire directement des fonctions comme $true
, $false
, $not
et même $fact
(factorial).
Async par défaut
Flow est conçu pour gérer efficacement les opérations asynchrones, garantissant que les tâches peuvent être exécutées simultanément sans bloquer d'autres processus. La programmation asynchrone est une fonctionnalité clé des applications modernes, permettant au système d'effectuer plusieurs opérations simultanément, telles que la gestion des tâches liées aux E/S, des appels réseau ou de toute tâche non bloquante.
Flow propose une manière structurée de gérer ces opérations asynchrones via un ensemble de pilotes. Chaque pilote fournit des fonctionnalités spécifiques, permettant aux développeurs d'implémenter la concurrence à l'aide de diverses approches telles que les coroutines, les fibres ou les boucles d'événements.
Pilotes actuellement implémentés
Flow prend actuellement en charge les pilotes suivants :
-
Amp Driver : un framework de concurrence pour PHP qui permet l'utilisation d'opérations asynchrones.
-
Fiber Driver : PHP 8.1 a introduit les fibres, qui offrent un support natif des coroutines.
-
ReactPHP Driver : une bibliothèque qui apporte des E/S non bloquantes pilotées par événements à PHP.
-
Spatie Driver : une bibliothèque de tâches asynchrones simple pour PHP, facilitant le travail avec la concurrence.
-
Swoole Driver : un framework de programmation asynchrone et de coroutine hautes performances pour PHP, idéal pour créer des applications Web à grande échelle et en temps réel.
Méthodes asynchrones de base dans Flow
Le modèle asynchrone de Flow s'articule autour de plusieurs méthodes clés qui sont implémentées dans DriverInterface
. Ces méthodes donnent aux développeurs un contrôle précis sur la façon dont les tâches asynchrones sont gérées dans leurs applications.
async(Closure|JobInterface $callback): Closure
La méthode async()
est conçue pour démarrer un processus asynchrone. Elle prend une Closure
ou une JobInterface
comme argument et renvoie une Closure
qui initie la tâche asynchrone lorsqu'elle est invoquée.
- Closure : il s'agit d'une fonction anonyme typique en PHP qui sera exécutée de manière asynchrone.
- JobInterface : cela permet une définition de tâche plus structurée, où le travail encapsule la logique de traitement et de gestion de l'opération asynchrone.
Le but de async()
est de mettre en file d'attente les tâches à exécuter sans bloquer le thread principal. Cela est particulièrement utile dans les situations où plusieurs tâches liées aux E/S ou coûteuses en calcul doivent s'exécuter simultanément.
Exemple d'utilisation :
$driver->async(function () {
// Some asynchronous task, such as making an HTTP request
});
Dans cet exemple, la fonction anonyme sera exécutée de manière asynchrone, ce qui permettra à d'autres tâches de continuer à s'exécuter en attendant la fin de cette opération.
defer(Closure $callback): mixed
La méthode defer()
permet un contrôle plus précis des tâches asynchrones en fournissant deux rappels à la tâche : un rappel d'achèvement et un rappel asynchrone. Cela permet de différer les tâches asynchrones, garantissant qu'elles ne bloquent pas d'autres processus en attendant l'étape suivante du flux.
- Le rappel d'achèvement est utilisé pour stocker le résultat de la tâche une fois qu'elle est terminée.
- Le rappel asynchrone est utilisé pour déclencher l'étape suivante de la chaîne asynchrone.
Cette méthode est particulièrement utile lorsque vous devez enchaîner des tâches asynchrones ou contrôler l'ordre dans lequel les tâches sont exécutées.
Exemple d'utilisation :
$driver->defer(function ($complete, $nextAsync) {
// Some asynchronous task
$complete($result); // Store the result
$nextAsync($result); // Move to the next async task
});
Ici, la méthode defer()
garantit que la tâche est correctement exécutée et, une fois terminée, elle passe à la tâche suivante tout en stockant le résultat pour une utilisation ultérieure.
await(array &$stream): void
La méthode await()
est utilisée pour attendre que toutes les opérations asynchrones d'un flux soient terminées avant de revenir à l'exécution synchrone. Cette méthode est essentielle pour garantir que toutes les tâches sont terminées avant de procéder à d'autres opérations synchrones.
Elle prend un tableau d'opérations, contenant généralement les fonctions de flux et les répartiteurs, et garantit que chaque tâche asynchrone de ce flux est terminée.
Cette méthode est utile dans les scénarios où vous souhaitez vous assurer que tous les processus asynchrones se terminent avant de passer à la partie suivante de la logique de votre application. Par exemple, si vous gérez plusieurs requêtes HTTP simultanément, vous pouvez utiliser await()
pour vous assurer que toutes les requêtes sont terminées avant de traiter les résultats.
Exemple d'utilisation :
$stream = [
'fnFlows' => [/* asynchronous flows */],
'dispatchers' => [/* event dispatchers */]
];
$driver->await($stream);
Dans ce cas, la méthode await()
garantit que toutes les opérations asynchrones au sein du flux ont été terminées avant de passer à l'étape synchrone suivante.
Résumé du modèle asynchrone de Flow
Les méthodes asynchrones de Flow offrent aux développeurs des options flexibles pour gérer la concurrence au sein des applications PHP. Avec des méthodes comme async()
, defer()
et await()
, Flow permet un contrôle précis sur la manière et le moment d'exécution des tâches asynchrones, garantissant que les applications peuvent gérer efficacement les opérations à grande échelle et en temps réel. De plus, la disponibilité de plusieurs pilotes permet une personnalisation en fonction des besoins de l'application, offrant une large gamme d'outils pour mettre en œuvre efficacement la programmation asynchrone.
Choisissez votre stratégie IP
Flow s'intègre au composant Symfony EventDispatcher, tirant parti de sa puissante architecture basée sur les événements pour gérer les paquets d'informations (IP) tout au long du flux. En utilisant les modèles de conception Mediator et Observer, Flow permet une orchestration dynamique pilotée par les événements, garantissant que chaque IP peut être traitée de manière flexible sans interférer avec d'autres composants du système. Cette architecture basée sur les événements reflète la façon dont Symfony gère les événements, offrant la même extensibilité et le même contrôle sur l'exécution du flux.
Voici comment les différentes stratégies IP sont implémentées dans Flow à l'aide de l'EventDispatcher :
- PUSH : Flow déclenche un événement « PUSH » au tout début, vous permettant de pousser une IP dans le flux avant le démarrage de tout processus asynchrone. Ceci est utile pour initialiser et mettre en file d'attente les IP pour un traitement ultérieur.
Exemple d'événement : « Flow\Event\PushEvent »
- ASYNC : L'événement « ASYNC » est envoyé lorsque Flow commence le traitement asynchrone d'une IP. Cela vous permet de gérer l'IP de manière asynchrone, offrant une flexibilité dans la façon dont les différentes étapes du flux sont exécutées simultanément.
Exemple d'événement : Flow\Event\AsyncEvent
- PULL : l'événement
PULL
est envoyé lorsque Flow doit extraire l'IP suivante pour un traitement asynchrone. Cela vous permet de définir la logique de sélection de l'IP qui sera traitée ensuite parmi les IP poussées.
Exemple d'événement : Flow\Event\PullEvent
- POP : lorsqu'une IP a terminé le traitement asynchrone, Flow déclenche un événement
POP
. Cet événement permet de s'assurer que l'IP a franchi toutes les étapes nécessaires et qu'elle est prête à passer au processus suivant dans le flux.
Exemple d'événement : Flow\Event\PopEvent
- POOL : l'événement
POOL
est utilisé lorsque Flow doit rassembler un pool d'IP pour le traitement. Cet événement permet de sélectionner dynamiquement des IP dans un pool pour un traitement simultané, permettant une orchestration efficace.
Exemple d'événement : Flow\Event\PoolEvent
En s'intégrant à l'EventDispatcher de Symfony, Flow offre une manière flexible et extensible de gérer les IP, garantissant que chaque étape du flux peut être personnalisée et étendue sans modifier la logique de base. Cela est similaire à la façon dont le système d'événements de Symfony permet de modifier des objets comme Response
dans le composant HttpKernel, où divers écouteurs peuvent modifier la réponse avant qu'elle ne soit renvoyée.
Cette approche offre des avantages significatifs, notamment :
- Extensibilité : de nouvelles fonctionnalités peuvent être introduites sans modifier la logique de flux de base, simplement en ajoutant de nouveaux écouteurs d'événements.
- Parallélisme : Flow prend naturellement en charge le traitement asynchrone et le système d'événements assure une gestion efficace de plusieurs IP simultanément.
- Séparation des préoccupations : chaque événement (PUSH, ASYNC, PULL, POP, POOL) gère des étapes spécifiques du traitement des IP, ce qui rend le système plus modulaire et plus facile à entretenir.
Exemple
L'exemple suivant montre à quel point Flow est puissant lorsqu'il s'agit de gérer la récursivité asynchrone. Dans ce code, Flow orchestre le calcul des nombres de Fibonacci à l'aide d'un processus asynchrone et non bloquant. Cela montre comment Flow gère efficacement la récursivité et l'exécution asynchrone, permettant à plusieurs tâches d'être exécutées simultanément sans verrouiller le système.
Composants clés de l'exemple
- Sélection du pilote : Le code sélectionne dynamiquement un pilote asynchrone (soit « AmpDriver », « ReactDriver », « FiberDriver » ou « SwooleDriver ») à l'aide de l'instruction « match », ajoutant de la flexibilité à la gestion des processus asynchrones. Chaque pilote apporte ses propres avantages uniques en fonction de l'environnement d'application.
$driver = match (random_int(1, 4)) {
1 => new AmpDriver(),
2 => new ReactDriver(),
3 => new FiberDriver(),
4 => new SwooleDriver(),
};
- Calcul de Fibonacci :
Le calcul de Fibonacci (
fibonacciYJobDefer
) est exécuté de manière récursive dans un cadre asynchrone. Cela signifie que, plutôt que de bloquer le programme en attendant le retour des appels récursifs, Flow permet au programme de continuer à exécuter d'autres tâches, rendant le calcul de Fibonacci efficace et non bloquant.
- Avant le calcul de Fibonacci :
Une tâche (
fibonacciYJobDeferBefore
) est définie pour initialiser et enregistrer le début du calcul de Fibonacci.
$fibonacciYJobDeferBefore = static function (YFlowData $data) {
printf("....* #%d - Job 5 : Calcul de fibonacciYJobDefer(%d)\n", $data->id, $data->number);
return new YFlowData($data->id, $data->number, $data->number);
};
- Calcul asynchrone de Fibonacci :
Le calcul récursif de Fibonacci se produit à l'intérieur de
fibonacciYJobDefer
. Ce travail utilise une gestion différée asynchrone, permettant au programme de traiter chaque étape en parallèle sans attendre que la séquence de Fibonacci entière soit calculée.
$fibonacciYJobDefer = new YJob(static function ($fibonacci) use ($driver) {
return static function ($args) use ($fibonacci, $driver) {
[$data, $defer] = $args;
return $defer(static function ($complete, $async) use ($data, $defer, $fibonacci, $driver) {
if ($data->result <= 1) {
$delay = random_int(1, 3);
printf("....* #%d - Job 5 : Step fibonacciYJobDefer(%d) with delay %d\n", $data->id, $data->number, $delay);
$driver->delay($delay);
$complete([new YFlowData($data->id, $data->number, 1), $defer]);
} else {
$async($fibonacci([new YFlowData($data->id, $data->number, $data->result - 1), $defer]), static function ($result1) use ($data, $complete, $driver, $async, $fibonacci) {
[$resultData1, $defer1] = $result1;
$async($fibonacci([new YFlowData($data->id, $data->number, $data->result - 2), $defer1]), static function ($result2) use ($data, $complete, $driver, $resultData1) {
[$resultData2, $defer2] = $result2;
$delay = random_int(1, 3);
printf("....* #%d - Job 5 : Step async fibonacciYJobDefer(%d) with delay %d\n", $data->id, $data->number, $delay);
$driver->delay($delay);
$fibResult = $resultData1->result + $resultData2->result;
$complete([new YFlowData($data->id, $data->number, $fibResult), $defer2]);
});
});
}
});
};
});
Cette étape démontre la puissance de Flow dans la gestion de la récursivité avec le traitement asynchrone. Les rappels async
permettent à plusieurs appels récursifs (pour F(n-1)
et F(n-2)
) de se produire en parallèle, et les résultats sont combinés une fois les deux terminés. Cette approche non bloquante empêche le blocage du système et permet à d'autres processus de s'exécuter simultanément.
- Après le calcul de Fibonacci :
Une fois le calcul de Fibonacci terminé, le résultat est enregistré à l'aide de la tâche
fibonacciYJobDeferAfter
.
$fibonacciYJobDeferAfter = static function ($args) {
[$data, $defer] = $args;
return $defer(static function ($complete) use ($data, $defer) {
printf("....* #%d - Job 5 : Result for fibonacciYJobDefer(%d) = %d\n", $data->id, $data->number, $data->result);
$complete([new YFlowData($data->id, $data->number), $defer]);
});
};
- Orchestration de flux : Le framework Flow orchestre l'intégralité du processus. Les étapes de calcul de Fibonacci sont définies comme une série de tâches qui sont générées et exécutées de manière asynchrone. Chaque tâche, y compris la préparation, la récursivité et la journalisation du résultat final, est traitée en séquence, mais sans bloquer le thread principal.
$flow = Flow::do(static function () use (
$fibonacciYJobDeferBefore,
$fibonacciYJobDefer,
$fibonacciYJobDeferAfter
) {
yield [$fibonacciYJobDeferBefore];
yield [$fibonacciYJobDefer, null, null, null, new DeferAsyncHandler()];
yield [$fibonacciYJobDeferAfter, null, null, null, new DeferAsyncHandler()];
}, ['driver' => $driver]);
- Traitement IP :
Enfin, le code crée et traite des paquets d'informations (
Ip
) pour chaque calcul, en les transmettant via le pipeline Flow. Le flux est ensuite attendu pour garantir que toutes les opérations asynchrones se terminent avant la fin du programme.
for ($i = 1; $i <= 5; $i++) {
$ip = new Ip(new YFlowData($i, $i));
$flow($ip);
}
$flow->await();
Qu'obtenons-nous ?
-
Récursivité asynchrone : la récursivité peut souvent être lourde en termes de performances et bloquer d'autres processus dans les systèmes traditionnels. Flow permet à la récursivité de se produire de manière asynchrone, ce qui signifie que d'autres tâches peuvent s'exécuter simultanément pendant que les appels récursifs s'exécutent, améliorant ainsi l'efficacité et la réactivité.
-
Flexibilité du pilote : la sélection dynamique du pilote permet à Flow de s'adapter à différents environnements, ce qui le rend très polyvalent. En fonction des besoins du système ou de l'application, Flow peut utiliser différents pilotes pour obtenir un comportement asynchrone.
-
Exécution non bloquante : en utilisant des rappels asynchrones et une gestion différée, cet exemple démontre la capacité de Flow à gérer plusieurs tâches simultanément, améliorant ainsi l'évolutivité et le rendant idéal pour les applications en temps réel.
-
Modulaire et extensible : chaque tâche (avant, pendant et après le calcul de Fibonacci) est modulaire, ce qui facilite l'extension ou la modification du flux de travail sans affecter le reste du système.
Installer Flow
Vous pouvez vous rendre sur l'url suivante pour plus de détails