Multiplexeur de canaux : défis et solutions
Introduction
En Go, un multiplexeur de canaux a pour objectif pour fusionner les sorties de plusieurs canaux en un seul canal cohérent. Pour atteindre cet objectif, une approche courante consiste à utiliser des goroutines pour surveiller chaque canal d'entrée et relayer les valeurs reçues vers le canal de sortie.
Défis rencontrés
Un utilisateur a partagé un extrait de code implémentant un multiplexeur, mais rencontrait plusieurs problèmes :
- Les goroutines recevaient des valeurs du même canal à la place de leurs canaux d'entrée prévus.
- Le canal de sortie ne contenait que les valeurs des 10 derniers canaux d'entrée.
- Le comportement d'alimentation était particulier, la sortie affichant uniquement la première valeur de chaque canal d'entrée.
Solutions
-
Passe-chaîne aux Goroutines : Le code original a transmis le même canal à plusieurs goroutines, ce qui a permis à toutes les goroutines d'extraire les valeurs de la même source. Ce problème peut être résolu en passant un canal distinct à chaque goroutine en utilisant la syntaxe de flèche :
for _, c := range channels {
go func(c <-chan big.Int) {
// ...
}(c)
}
Copier après la connexion
-
синхронизация : при использовании sync.WaitGroup : Le code utilisé un simple compteur (n) pour suivre la fermeture des canaux d'entrée et fermer le canal de sortie en conséquence. Cependant, dans un environnement concurrent avec plusieurs goroutines, cette approche est sensible aux conditions de concurrence. Le passage à un sync.WaitGroup garantit que le canal de sortie n'est fermé qu'une fois que toutes les goroutines ont terminé leurs opérations.
-
Comportement d'alimentation : Le comportement d'alimentation inhabituel était dû au manque de synchronisation dans le recevoir des goroutines. Cela a conduit à une situation dans laquelle un goroutine pouvait capturer plusieurs valeurs de son canal d'entrée avant qu'un autre goroutine ait la chance de recevoir des valeurs. Pour résoudre ce problème, l'ajout d'une minuterie de mise en veille entre les récupérations de valeurs successives peut aider à limiter le nombre de valeurs que chaque goroutine reçoit en une seule itération.
-
Approche alternative : En plus des correctifs mentionnés ci-dessus , une autre alternative consiste à utiliser la fonction Reflect.Select intégrée pour surveiller plusieurs canaux et recevoir sélectivement des valeurs en fonction de l'état de préparation du canal. Cette approche peut simplifier le code et améliorer les performances dans certains scénarios.
Extrait de code amélioré
L'extrait de code mis à jour intégrant les améliorations suggérées :
import (
"math/big"
"sync"
)
func Mux(channels []chan big.Int) chan big.Int {
var wg sync.WaitGroup
wg.Add(len(channels))
ch := make(chan big.Int, len(channels))
for _, c := range channels {
go func(c <-chan big.Int) {
for x := range c {
ch <- x
}
wg.Done()
}(c)
}
go func() {
wg.Wait()
close(ch)
}()
return ch
}
Copier après la connexion
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!