Introducción
Este laboratorio tiene como objetivo demostrar cómo utilizar mutexes para acceder de manera segura a datos a través de múltiples goroutines.
This tutorial is from open-source community. Access the source code
💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí
Este laboratorio tiene como objetivo demostrar cómo utilizar mutexes para acceder de manera segura a datos a través de múltiples goroutines.
El problema que se debe resolver en este laboratorio es incrementar un contador nombrado en un bucle utilizando múltiples goroutines y asegurarse de que el acceso al contador esté sincronizado.
Container
para almacenar un mapa de contadores.Mutex
para sincronizar el acceso al mapa counters
.Container
debe tener un método inc
que tome una cadena name
e incremente el contador correspondiente en el mapa counters
.inc
debe bloquear el mutex antes de acceder al mapa counters
y desbloquearlo al final de la función utilizando una declaración defer
.sync.WaitGroup
para esperar a que las goroutines terminen.fmt.Println
para imprimir el mapa counters
.## Ejecutar el programa muestra que los contadores
## se actualizan como se esperaba.
## A continuación, veremos cómo implementar esta misma tarea
## de administración de estado utilizando solo goroutines y canales.
A continuación se muestra el código completo:
// En el ejemplo anterior vimos cómo administrar un estado
// de contador simple utilizando [operaciones atómicas](atomic-counters).
// Para un estado más complejo, podemos utilizar un [_mutex_](https://en.wikipedia.org/wiki/Mutual_exclusion)
// para acceder de manera segura a datos a través de múltiples goroutines.
package main
import (
"fmt"
"sync"
)
// Container almacena un mapa de contadores; dado que queremos
// actualizarlo concurrentemente desde múltiples goroutines,
// agregamos un `Mutex` para sincronizar el acceso.
// Tenga en cuenta que los mutexes no deben ser copiados,
// por lo que si esta `struct` se pasa por ahí, debe hacerse
// por puntero.
type Container struct {
mu sync.Mutex
counters map[string]int
}
func (c *Container) inc(name string) {
// Bloque el mutex antes de acceder a `counters`; desbloque
// it al final de la función utilizando una declaración [defer](defer).
c.mu.Lock()
defer c.mu.Unlock()
c.counters[name]++
}
func main() {
c := Container{
// Tenga en cuenta que el valor cero de un mutex es usable tal cual,
// por lo que no es necesario inicializarlo aquí.
counters: map[string]int{"a": 0, "b": 0},
}
var wg sync.WaitGroup
// Esta función incrementa un contador nombrado
// en un bucle.
doIncrement := func(name string, n int) {
for i := 0; i < n; i++ {
c.inc(name)
}
wg.Done()
}
// Ejecute varias goroutines concurrentemente; tenga en cuenta
// que todas acceden al mismo `Container`,
// y dos de ellas acceden al mismo contador.
wg.Add(3)
go doIncrement("a", 10000)
go doIncrement("a", 10000)
go doIncrement("b", 10000)
// Espere a que las goroutines terminen
wg.Wait()
fmt.Println(c.counters)
}
En este laboratorio, aprendimos cómo utilizar mutexes para acceder de manera segura a datos a través de múltiples goroutines. Creamos una estructura Container
para almacenar un mapa de contadores y utilizamos un Mutex
para sincronizar el acceso al mapa counters
. También implementamos un método inc
para incrementar el contador nombrado y utilizamos la estructura sync.WaitGroup
para esperar a que las goroutines terminen. Finalmente, imprimimos el mapa counters
utilizando la función fmt.Println
.