Maison > développement back-end > Golang > Modèle de concurrence de pipeline dans Go : un guide visuel complet

Modèle de concurrence de pipeline dans Go : un guide visuel complet

DDD
Libérer: 2024-12-31 14:23:11
original
493 Les gens l'ont consulté

⚠️ Comment s'y prendre pour cette série ?

1. Exécutez chaque exemple : Ne vous contentez pas de lire le code. Tapez-le, exécutez-le et observez le comportement.
2. Expérimentez et cassez des choses : Supprimez les mises en veille et voyez ce qui se passe, modifiez la taille des tampons de canal, modifiez le nombre de goroutines.
Casser des choses vous apprend comment elles fonctionnent
3. Raison concernant le comportement : Avant d'exécuter du code modifié, essayez de prédire le résultat. Lorsque vous constatez un comportement inattendu, faites une pause et réfléchissez à pourquoi. Contestez les explications.
4. Construire des modèles mentaux : Chaque visualisation représente un concept. Essayez de dessiner vos propres diagrammes pour le code modifié.

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Dans notre article précédent, nous avons exploré le modèle de simultanéité Generator, les éléments constitutifs des autres modèles de simultanéité de Go. Vous pouvez le lire ici :

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Modèle de concurrence de générateur dans Go : un guide visuel

Souvik Kar Mahapatra ・ 25 décembre

#aller #tutoriel #programmation #apprentissage

Voyons maintenant comment ces primitives se combinent pour former des modèles puissants qui résolvent des problèmes du monde réel.

Dans cet article, nous aborderons le Modèle de pipeline et essaierons de les visualiser. Alors préparons-nous car nous serons présents tout au long du processus.

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Modèle de pipeline

Un pipeline est comme une chaîne de montage dans une usine, où chaque étape effectue une tâche spécifique sur les données et transmet le résultat à l'étape suivante.

Nous construisons des pipelines en connectant les goroutines avec des canaux, où chaque goroutine représente une étape qui reçoit les données, les traite et les envoie à l'étape suivante.

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Implémentons un pipeline simple qui :

  1. Génère des nombres
  2. Les met au carré
  3. Imprime les résultats
// Stage 1: Generate numbers
func generate(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            out <- n
        }
    }()
    return out
}

// Stage 2: Square numbers
func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            out <- n * n
        }
    }()
    return out
}

// Stage 3: Print numbers
func print(in <-chan int) {
    for n := range in {
        fmt.Printf("%d ", n)
    }
    fmt.Println()
}

func main() {
    // Connect the pipeline
    numbers := generate(2, 3, 4)    // Stage 1
    squares := square(numbers)       // Stage 2
    print(squares)                   // Stage 3
}
Copier après la connexion
Copier après la connexion

✏️ Octet rapide

<-chan int désigne un canal de réception uniquement.
Un canal de type <-chan int ne peut être utilisé que pour recevoir des valeurs, pas pour les envoyer. Ceci est utile pour appliquer des modèles de communication plus stricts et empêcher les écritures accidentelles sur le canal par le récepteur.

chan int Cela désigne un canal bidirectionnel.
Un canal de type chan int peut être utilisé à la fois pour envoyer et recevoir des valeurs.

Allons-y et visualisons l'exemple ci-dessus :

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Ici, vous pouvez voir que chacun des éléments constitutifs du pipeline est des goroutines suivant le modèle du générateur. Cela implique que dès que les données sont prêtes à n'importe quelle étape, l'étape suivante du pipeline peut commencer à les traiter contrairement au traitement séquentiel.

Gestion des erreurs dans les pipelines

Les principes fondamentaux devraient être :

  1. Chaque étape sait exactement quoi faire des bonnes et des mauvaises valeurs
  2. Les erreurs ne peuvent pas se perdre dans le pipeline
  3. Les mauvaises valeurs ne provoquent pas de panique
  4. Le message d'erreur contient un contexte sur ce qui n'a pas fonctionné
  5. Le pipeline peut être étendu avec plus d'étapes, et elles géreront toutes les erreurs de manière cohérente

Mettons à jour notre code avec une gestion appropriée des erreurs.

type Result struct {
    Value int
    Err   error
}

func generateWithError(nums ...int) <-chan Result {
    out := make(chan Result)
    go func() {
        defer close(out)
        for _, n := range nums {
            if n < 0 {
                out <- Result{Err: fmt.Errorf("negative number: %d", n)}
                return
            }
            out <- Result{Value: n}
        }
    }()
    return out
}

func squareWithError(in <-chan Result) <-chan Result {
    out := make(chan Result)
    go func() {
        defer close(out)
        for r := range in {
            if r.Err != nil {
                out <- r  // Forward the error
                continue
            }
            out <- Result{Value: r.Value * r.Value}
        }
    }()
    return out
}

func main() {
    // Using pipeline with error handling
    for result := range squareWithError(generateWithError(2, -3, 4)) {
        if result.Err != nil {
            fmt.Printf("Error: %v\n", result.Err)
            continue
        }
        fmt.Printf("Result: %d\n", result.Value)
    }
}
Copier après la connexion

Pourquoi utiliser le modèle de pipeline ?

Prenons un exemple pour mieux comprendre, nous avons un workflow de traitement de données qui suit le modèle de pipeline comme indiqué ci-dessous.

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

  1. Chaque étape d'un pipeline fonctionne indépendamment et communique uniquement via des canaux. Cela permet plusieurs avantages :

? Chaque étape peut être développée, testée et modifiée indépendamment
? Les modifications apportées aux éléments internes d'une étape n'affectent pas les autres étapes
? Facile d'ajouter de nouvelles étapes ou de modifier celles existantes
? Séparation claire des préoccupations

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

  1. Les modèles de pipeline permettent naturellement un traitement parallèle/simultané. Chaque étape peut traiter différentes données simultanément dès que les données sont disponibles.

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Et le meilleur ? Nous pouvons exécuter plusieurs instances de chaque étape (travailleurs) pour des exigences plus simultanées comme ceci :

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

?? Hé, mais n'est-ce pas le Modèle de concurrence Fan-In et Fan-Out ?

Bingo ! Bonne prise là. Il s’agit en effet d’un modèle Fan-Out, Fan-In, qui est un type spécifique de modèle de pipeline. Nous allons en parler en détail dans notre prochain article, alors ne vous inquiétez pas ;)

Cas d'utilisation réel

traitement des images dans un pipeline

// Stage 1: Generate numbers
func generate(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            out <- n
        }
    }()
    return out
}

// Stage 2: Square numbers
func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            out <- n * n
        }
    }()
    return out
}

// Stage 3: Print numbers
func print(in <-chan int) {
    for n := range in {
        fmt.Printf("%d ", n)
    }
    fmt.Println()
}

func main() {
    // Connect the pipeline
    numbers := generate(2, 3, 4)    // Stage 1
    squares := square(numbers)       // Stage 2
    print(squares)                   // Stage 3
}
Copier après la connexion
Copier après la connexion

ou quelque chose d'aussi compliqué qu'un pipeline de traitement des journaux

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Modèles de mise à l'échelle du pipeline

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Mise à l'échelle horizontale (Fan-Out, Fan-In)

Ce modèle est idéal pour les opérations liées au processeur où le travail peut être traité indépendamment. Le pipeline répartit le travail entre plusieurs nœuds de calcul, puis recombine les résultats. Ceci est particulièrement efficace lorsque :

  1. Les traitements sont gourmands en CPU (transformations de données, calculs)
  2. Les tâches peuvent être traitées indépendamment
  3. Vous disposez de plusieurs cœurs de processeur disponibles

Pipeline tamponné

Ce modèle permet de gérer les écarts de vitesse entre les étapes du pipeline. Le tampon agit comme un amortisseur, permettant aux étapes rapides d'avancer sans être bloquées par des étapes plus lentes. Ceci est utile lorsque :

  1. Différentes étapes ont des vitesses de traitement variables
  2. Vous souhaitez maintenir un débit stable
  3. L'utilisation de la mémoire pour la mise en mémoire tampon est acceptable
  4. Vous devez gérer le traitement en rafale

Traitement par lots

Ce modèle optimise les opérations liées aux E/S en regroupant plusieurs éléments en un seul lot. Au lieu de traiter les éléments un par un, il les rassemble en groupes et les traite ensemble. Ceci est efficace lorsque :

  1. Vous travaillez avec des systèmes externes (bases de données, API)
  2. Les allers-retours réseau coûtent cher
  3. L'opération entraîne des frais généraux fixes importants par requête
  4. Vous devez optimiser le débit par rapport à la latence

Chacun de ces modèles peut être combiné selon les besoins. Par exemple, vous pouvez utiliser le traitement par lots avec mise à l'échelle horizontale, dans lequel plusieurs travailleurs traitent chacun des lots d'éléments. La clé est de comprendre vos goulots d'étranglement et de choisir le modèle approprié pour les résoudre.


Cela conclut notre plongée profonde dans le modèle Generator ! Dans la prochaine étape, nous explorerons le modèle de concurrence concurrentielle du pipeline, où nous verrons comment enchaîner nos générateurs pour créer de puissants flux de traitement de données.

Si vous avez trouvé cet article utile, si vous avez des questions ou si vous souhaitez partager vos propres expériences avec les générateurs, j'aimerais avoir de vos nouvelles dans les commentaires ci-dessous. Vos idées et vos questions contribuent à rendre ces explications encore meilleures pour tout le monde.

Si vous avez manqué le guide visuel de la goroutine et des chaînes de Golang, consultez-le ici :

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Comprendre et visualiser les Goroutines et les canaux en Golang

Souvik Kar Mahapatra ・ 20 décembre

#aller #programmation #apprentissage #tutoriel

Restez à l'écoute pour plus de modèles de concurrence Go ! ?

Pipeline Concurrency Pattern in Go: A Comprehensive Visual Guide

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal