Saltar al contenido principal
eLearner.app
Módulo 7 · Lección 4 de 534/50 en el curso~14 min
Lecciones del módulo (4/5)

sync.Mutex y sync.WaitGroup

Los canales son el idioma principal de Go, pero a veces son más tradicionales. Se necesitan primitivos. El paquete sync proporciona mutex, espere grupos y otras utilidades para coordinar el estado compartido.

sync.Mutex: bloqueo exclusivo

Go
import "sync"

type Counter struct {
    mu    sync.Mutex
    count int
}

func (c *Counter) Inc() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func (c *Counter) Get() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

Solo una gorutina a la vez ingresa entre Lock() y Unlock(). Patrón obligatorio: defer mu.Unlock() justo después de Lock().

sync.RWMutex: muchos lectores, un escritor

Para estado de lectura intensa:

Go
var mu sync.RWMutex

mu.RLock()              // read lock: più goroutine simultanee OK
v := data
mu.RUnlock()

mu.Lock()               // write lock: esclusivo
data = newValue
mu.Unlock()

Útil sólo si las lecturas realmente dominan sobre las escrituras; de lo contrario un regular sync.Mutex es más simple y a menudo más rápido gracias a una menor interna contención.

sync.WaitGroup: espera N gorutinas

Go
var wg sync.WaitGroup

for i := 0; i < 3; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        work(id)
    }(i)
}
wg.Wait()    // blocca finché tutti i Done() sono arrivati

Flujo de trabajo:

  1. wg.Add(N) incrementa el contador en N (antes de lanzar las gorutinas).
  2. Cada gorutina llama a wg.Done() cuando finaliza (idealmente a través de defer).
  3. wg.Wait() se bloquea hasta que el contador vuelve a 0.

sync.Once: inicialización diferida segura para subprocesos

Go
var (
    once   sync.Once
    config *Config
)

func GetConfig() *Config {
    once.Do(func() {
        config = loadConfig()
    })
    return config
}

La devolución de llamada en once.Do se ejecuta exactamente una vez, incluso en condiciones concurrentes. llamadas. Patrón de inicialización singleton/perezoso.

Mutex vs canal: cuándo usar qué

Directrices (también de las preguntas frecuentes oficiales de Go):

CasoHerramienta preferida
Transferencia de propiedad de los datoscanal
Distribución de trabajo (cola de trabajo)canal
Coordinación de gorutinas independientescanal
Protegiendo un campo de estructuraMutex
Caché/contadorMutex o atómico
Referencia únicaCÓDIGOPH0

"Canales para orquestar, exclusiones mutuas para datos compartidos" es una buena regla general.

Detector de carrera

Ejecute pruebas con -race para detectar carreras de datos:

Bash
go test -race ./...
go run -race main.go

El detector de carreras instrumenta el binario y registra todos los no sincronizados. acceso a la memoria compartida. Es la herramienta número 1 para validar código concurrente. antes de la producción.

Pruébalo

Ejercicio#go.m7.l4.e1
Intentos: 0Cargando...

Proteja el incremento del recuento con mu.Lock() + diferir mu.Unlock().

Cargando editor...
Mostrar pista

diferir mu.Unlock() justo después de Lock() garantiza la liberación incluso en caso de pánico.

Solución disponible después de 3 intentos

Ejercicio#go.m7.l4.e2
Intentos: 0Cargando...

Inicie 3 goroutines y espere todas ellas usando sync.WaitGroup (Add(3), Done() en cada goroutine, Wait()).

Cargando editor...
Mostrar pista

Agregue ANTES de iniciar la rutina; Hecho DENTRO de la rutina con aplazamiento.

Solución disponible después de 3 intentos

Cuestionario#go.m7.l4.e3
Listo

¿Cuál es el patrón recomendado para garantizar que se libere el mutex?

Go
mu.Lock()
// ?
Opciones de respuesta

Resumen

  • sync.Mutex protege el estado compartido; siempre CÓDIGOPH1.
  • Utilice un receptor de puntero para evitar copiar el mutex.
  • sync.RWMutex para patrones de muchos lectores/un escritor (solo si ayuda).
  • sync.WaitGroup: Add antes de go, Done con defer, Wait a la espera.
  • sync.Once: inicialización diferida segura para subprocesos.
  • "Canales para orquestar, mutexes para datos compartidos".
  • defer mu.Unlock()0: herramienta n.° 1 para detectar carreras de datos.