Créa-blog

Ressources pour développeur web

Utiliser les Fiber ou Fibre en PHP : Tutoriel avec Exemples

Accueil PHP 8 Utiliser les Fiber ou Fibre en PHP : Tutoriel avec Exemples

Les Fiber ou fibre en PHP permettent une gestion asynchrone et coopérative des tâches. Elles offrent une alternative légère aux threads et aux processus, permettant aux développeurs de gérer des opérations de manière non bloquante. Ce tutoriel vous guidera dans l’utilisation des fibres en PHP, ainsi que des exemples pratiques pour illustrer leur utilisation.

Qu’est-ce qu’une fibre ?

Une fibre est une unité d’exécution légère qui permet de suspendre et de reprendre des fonctions à des points spécifiques sans bloquer le thread principal. Cela permet d’écrire du code asynchrone de manière plus lisible et maintenable.

Création et Utilisation de Fibre en PHP

Prenons un exemple simple pour comprendre comment créer et utiliser une fibre en PHP :

$fibre = new Fiber(function() {
    echo "Début de la fibre\n";
    Fiber::suspend();
    echo "Reprise de la fibre\n";
});

echo "Avant démarrage de la fibre\n";
$fibre->start();
echo "Après démarrage de la fibre\n";
$fibre->resume();
echo "Après reprise de la fibre\n";
  • Création de la fibre : Une nouvelle fibre est créée avec new Fiber, en lui passant une fonction de callback.
  • Suspension de la fibre : À l’intérieur de la fonction de callback, Fiber::suspend() suspend l’exécution de la fibre.
  • Démarrage de la fibre : La fibre est démarrée avec $fibre->start().
  • Reprise de la fibre : La fibre suspendue est reprise avec $fibre->resume().

Le résultat :

Avant démarrage de la fibre
Début de la fibre
Après démarrage de la fibre
Reprise de la fibre
Après reprise de la fibre

La gestion asynchrone d’un fibre en PHP

Les fibres peuvent être particulièrement utiles pour des opérations asynchrones comme les requêtes HTTP ou l’accès à des bases de données. Voici un exemple simulant des opérations asynchrones :

function asyncOperation($id) {
    return new Fiber(function() use ($id) {
        echo "Opération $id commencée\n";
        Fiber::suspend();
        echo "Opération $id terminée\n";
    });
}

$operations = [];
for ($i = 1; $i <= 3; $i++) {
    $operations[] = asyncOperation($i);
}

foreach ($operations as $operation) {
    $operation->start();
}

echo "Toutes les opérations sont démarrées\n";

foreach ($operations as $operation) {
    $operation->resume();
}

echo "Toutes les opérations sont terminées\n";
  • Fonction asyncOperation : Cette fonction crée et retourne une fibre simulant une opération asynchrone.
  • Démarrage des opérations : Les fibres sont démarrées dans une boucle.
  • Reprise des opérations : Les fibres sont reprises dans une autre boucle, simulant une attente ou un traitement asynchrone.

Résultat de l’exécution :

Opération 1 commencée
Opération 2 commencée
Opération 3 commencée
Toutes les opérations sont démarrées
Opération 1 terminée
Opération 2 terminée
Opération 3 terminée
Toutes les opérations sont terminées

Pourquoi Utiliser des Fibres ?

Les fibres offrent plusieurs avantages clés qui en font un outil puissant pour les développeurs PHP, notamment :

Concurrence Coopérative : Contrairement aux threads, les fibres permettent une concurrence coopérative. Cela signifie que le développeur contrôle explicitement quand une fibre se suspend et se reprend, offrant ainsi une gestion plus prévisible des ressources et du flux de programme.

Code Asynchrone Lisible : Les fibres rendent le code asynchrone plus linéaire et lisible. Plutôt que d’utiliser des callbacks ou des promesses, les développeurs peuvent écrire du code asynchrone de manière séquentielle, ce qui simplifie la compréhension et la maintenance du code.

Léger et Performant : Les fibres sont plus légères que les threads et n’impliquent pas les coûts associés à la création et à la gestion des threads ou des processus. Cela les rend particulièrement utiles pour les applications nécessitant un grand nombre de tâches concurrentes.

Amélioration de la Réactivité : Les fibres permettent de maintenir une réactivité élevée des applications web en évitant de bloquer le thread principal. Par exemple, des opérations de lecture/écriture de fichiers, des requêtes réseau ou des accès à une base de données peuvent être effectuées de manière non bloquante.

Quand Utiliser des Fibres ?

Voici quelques scénarios où l’utilisation des fibres peut s’avérer bénéfique :

I/O Asynchrone : Lorsque votre application doit gérer des opérations d’entrée/sortie (I/O) qui peuvent prendre du temps (par exemple, appels API, requêtes base de données, accès fichiers), les fibres peuvent éviter de bloquer le thread principal.

Tâches Concurrentes Légères : Pour des tâches nécessitant une exécution concurrente mais qui ne justifient pas l’utilisation de threads lourds, comme des calculs ou traitements parallèles légers.

Systèmes Temps Réel : Dans les applications où la réactivité est critique, comme les systèmes temps réel ou les jeux en ligne, les fibres peuvent aider à maintenir une réactivité élevée.

Microservices et APIs : Les microservices et les APIs peuvent bénéficier des fibres pour gérer des requêtes multiples simultanément sans bloquer, améliorant ainsi les performances globales et le temps de réponse.

Exemple concret : Traitement parallèle de fichiers avec les Fibres en PHP

Le traitement parallèle de fichiers est une tâche courante qui peut grandement bénéficier de l’utilisation des fibres en PHP. Grâce aux fibres, nous pouvons lire, traiter et écrire des fichiers de manière concurrente sans bloquer le thread principal, ce qui améliore les performances et la réactivité de l’application.

Dans l’exemple ci-dessous, nous lisons plusieurs fichiers, effectuons un traitement sur leur contenu (par exemple, convertir le texte en majuscules), puis écrivons le contenu modifié dans de nouveaux fichiers :

// Fonction pour simuler la lecture d'un fichier
function readFileContents($filename) {
    return new Fiber(function() use ($filename) {
        echo "Lecture du fichier $filename\n";
        $content = file_get_contents($filename);
        Fiber::suspend($content); // Suspend la fibre et retourne le contenu du fichier
    });
}

// Fonction pour simuler le traitement du contenu du fichier
function processContents($content) {
    return new Fiber(function() use ($content) {
        echo "Traitement du contenu\n";
        $processedContent = strtoupper($content); // Convertit le contenu en majuscules
        Fiber::suspend($processedContent); // Suspend la fibre et retourne le contenu traité
    });
}

// Fonction pour écrire le contenu traité dans un nouveau fichier
function writeFileContents($filename, $content) {
    return new Fiber(function() use ($filename, $content) {
        echo "Écriture du fichier $filename\n";
        file_put_contents($filename, $content);
        Fiber::suspend(); // Suspend la fibre une fois l'écriture terminée
    });
}

$filenames = [
    "file1.txt",
    "file2.txt",
    "file3.txt"
];

$readFibers = [];
$processFibers = [];
$writeFibers = [];

// Lecture des fichiers en utilisant les fibres
foreach ($filenames as $filename) {
    $fiber = readFileContents($filename);
    $fiber->start();
    $readFibers[] = $fiber;
}

$contents = [];
foreach ($readFibers as $fiber) {
    $contents[] = $fiber->resume(); // Reprend la fibre et récupère le contenu du fichier
}

// Traitement des contenus en utilisant les fibres
foreach ($contents as $content) {
    $fiber = processContents($content);
    $fiber->start();
    $processFibers[] = $fiber;
}

$processedContents = [];
foreach ($processFibers as $fiber) {
    $processedContents[] = $fiber->resume(); // Reprend la fibre et récupère le contenu traité
}

// Écriture des contenus traités dans de nouveaux fichiers en utilisant les fibres
for ($i = 0; $i < count($processedContents); $i++) {
    $filename = "processed_" . $filenames[$i];
    $fiber = writeFileContents($filename, $processedContents[$i]);
    $fiber->start();
    $writeFibers[] = $fiber;
}

foreach ($writeFibers as $fiber) {
    $fiber->resume(); // Reprend la fibre pour terminer l'écriture
}

echo "Tous les fichiers ont été traités et écrits.\n";

Fonctions de Lecture, Traitement et Écriture :

  • readFileContents : Cette fonction crée une fibre qui lit le contenu d’un fichier et suspend l’exécution en renvoyant le contenu lu.
  • processContents : Cette fonction crée une fibre qui traite le contenu (par exemple, en le convertissant en majuscules) et suspend l’exécution en renvoyant le contenu traité.
  • writeFileContents : Cette fonction crée une fibre qui écrit le contenu traité dans un nouveau fichier et suspend l’exécution une fois l’écriture terminée.

Lecture des Fichiers :
Les fichiers sont lus de manière concurrente en démarrant une fibre pour chaque fichier. Les fibres sont stockées dans un tableau.

Traitement des Contenus :
Les contenus des fichiers lus sont repris (en reprenant les fibres), puis traités de manière concurrente en démarrant une fibre pour chaque contenu. Les fibres de traitement sont également stockées dans un tableau.

Écriture des Contenus Traités :
Les contenus traités sont repris (en reprenant les fibres de traitement), puis écrits dans de nouveaux fichiers de manière concurrente en démarrant une fibre pour chaque fichier. Les fibres d’écriture sont également stockées dans un tableau.

Reprise des Fibres :
Les fibres d’écriture sont reprises pour terminer l’écriture des fichiers traités.

Les fibres en PHP sont une solution élégante pour gérer des tâches asynchrones et concurrentes de manière plus simple et plus efficace. Elles permettent d’écrire du code asynchrone lisible et maintenable tout en offrant des performances élevées grâce à leur légèreté. Utiliser les fibres dans des scénarios appropriés peut améliorer la réactivité et la performance de vos applications PHP, en particulier lorsque des opérations de longue durée ou des tâches concurrentes sont impliquées.