Introduction
Ce laboratoire vise à démontrer comment utiliser des mutex pour accéder en toute sécurité à des données à travers plusieurs goroutines.
This tutorial is from open-source community. Access the source code
💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici
Ce laboratoire vise à démontrer comment utiliser des mutex pour accéder en toute sécurité à des données à travers plusieurs goroutines.
Le problème à résoudre dans ce laboratoire est d'incrémenter un compteur nommé dans une boucle en utilisant plusieurs goroutines, et de s'assurer que l'accès au compteur est synchronisé.
Container
pour stocker une carte de compteurs.Mutex
pour synchroniser l'accès à la carte counters
.Container
devrait avoir une méthode inc
qui prend une chaîne de caractères name
et incrémente le compteur correspondant dans la carte counters
.inc
devrait verrouiller le mutex avant d'accéder à la carte counters
, et le déverrouiller à la fin de la fonction en utilisant une instruction defer
.sync.WaitGroup
pour attendre que les goroutines se terminent.fmt.Println
pour imprimer la carte counters
.## Exécution du programme montre que les compteurs
## sont mis à jour comme prévu.
## Ensuite, nous allons voir comment implémenter cette même tâche
## de gestion d'état en utilisant seulement des goroutines et des canaux.
Voici le code complet ci-dessous :
// Dans l'exemple précédent, nous avons vu comment gérer un état
// de compteur simple en utilisant [opérations atomiques](atomic-counters).
// Pour un état plus complexe, nous pouvons utiliser un [_mutex_](https://en.wikipedia.org/wiki/Mutual_exclusion)
// pour accéder en toute sécurité à des données à travers plusieurs goroutines.
package main
import (
"fmt"
"sync"
)
// Container stocke une carte de compteurs ; comme nous voulons
// la mettre à jour de manière concurrente à partir de plusieurs goroutines,
// nous ajoutons un `Mutex` pour synchroniser l'accès.
// Notez que les mutexes ne doivent pas être copiés, donc si cette
// `struct` est passée en boucle, cela devrait être fait par
// pointeur.
type Container struct {
mu sync.Mutex
counters map[string]int
}
func (c *Container) inc(name string) {
// Verrouillez le mutex avant d'accéder à `counters` ; déverrouillez
// le à la fin de la fonction en utilisant une instruction [defer](defer).
c.mu.Lock()
defer c.mu.Unlock()
c.counters[name]++
}
func main() {
c := Container{
// Notez que la valeur zéro d'un mutex est utilisable telle quelle, donc
// aucune initialisation n'est requise ici.
counters: map[string]int{"a": 0, "b": 0},
}
var wg sync.WaitGroup
// Cette fonction incrémente un compteur nommé
// dans une boucle.
doIncrement := func(name string, n int) {
for i := 0; i < n; i++ {
c.inc(name)
}
wg.Done()
}
// Exécutez plusieurs goroutines en parallèle ; notez
// qu'elles accèdent toutes au même `Container`,
// et deux d'entre elles accèdent au même compteur.
wg.Add(3)
go doIncrement("a", 10000)
go doIncrement("a", 10000)
go doIncrement("b", 10000)
// Attendez que les goroutines se terminent
wg.Wait()
fmt.Println(c.counters)
}
Dans ce laboratoire, nous avons appris comment utiliser des mutex pour accéder en toute sécurité à des données à travers plusieurs goroutines. Nous avons créé une structure Container
pour stocker une carte de compteurs, et utilisé un Mutex
pour synchroniser l'accès à la carte counters
. Nous avons également implémenté une méthode inc
pour incrémenter le compteur nommé, et utilisé la structure sync.WaitGroup
pour attendre que les goroutines se terminent. Enfin, nous avons imprimé la carte counters
en utilisant la fonction fmt.Println
.