ProgramaciónDesarrollador Backend

¿Cuáles son las variantes de sincronización en Go? ¿Cómo usar sync.Mutex, sync.RWMutex y sync.WaitGroup, y qué matices existen en cada caso?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

En Go, para la sincronización de gorutinas concurrentes, se utilizan estructuras del paquete sync, siendo las más comunes sync.Mutex, sync.RWMutex y sync.WaitGroup.

sync.Mutex proporciona mecanismos de exclusión mutua para el acceso a datos compartidos. Sus métodos son Lock() (bloquea) y Unlock() (desbloquea).

sync.RWMutex amplía las capacidades del mutex estándar: permite lecturas paralelas, pero modifica exclusivamente.

sync.WaitGroup está diseñado para esperar a que un grupo de gorutinas finalice. Con Add(int), Done() y Wait(), se gestiona el ciclo de vida del trabajo paralelo.

Por ejemplo:

var mu sync.RWMutex data := 0 // Lectura mu.RLock() fmt.Println(data) mu.RUnlock() // Escritura mu.Lock() data = 42 mu.Unlock()

Matices:

  • Siempre utiliza Unlock en un bloque defer para no olvidar desbloquear el mutex incluso en caso de pánico.
  • Asegúrate de que el número de llamadas a WaitGroup.Done() corresponda a Add().
  • ¡No copies WaitGroup, Mutex ni RWMutex!

Pregunta capciosa

¿Se puede capturar el mismo sync.Mutex (o RWMutex) dos veces consecutivas en la misma gorutina? ¿Qué sucederá?

Respuesta: No, si llamas a Lock() en el mismo Mutex dos veces seguidas sin un Unlock() intermedio, la gorutina se bloqueará para siempre (deadlock). En Go, los mutex no son recursivos.

Ejemplo:

var mu sync.Mutex mu.Lock() // ... mu.Lock() // DEADLOCK: se bloqueará para siempre, ya que el mismo hilo ya tiene el bloqueo

Ejemplos de errores reales


Historia

En un proyecto para una API REST de alta carga, un desarrollador encapsuló todo el procesamiento de la solicitud con un único mutex. Esto provocó una caída brusca del rendimiento: solo se podía procesar una solicitud a la vez, aunque se planeaba atender a miles de clientes. La razón fue el desconocimiento de la diferencia entre Mutex y RWMutex y la ignorancia de las lecturas paralelas.


Historia

Al copiar una estructura con Mutex en su interior por uno de los miembros del equipo, accidentalmente se pasó una copia a otra función. Esto llevó a un mensaje de pánico "sync: copy of sync.Mutex" y a caídas en producción bajo alta carga.


Historia

Al usar WaitGroup, olvidaron llamar a Done() en varias gorutinas, lo que provocó una espera infinita en Wait(), bloqueando el hilo principal. Como resultado, el servicio perdió disponibilidad hasta que se reinició manualmente.