Contenido del curso
Concurrencia
- 2

Condiciones de Carrera en Programación Concurrente con Go
Viendo ahora - 3

Evitar Condiciones de Carrera en Go con Mutex y WaitGroup
11:26 min - 4

Lectura y Escritura Concurrente en Go con RWMutex
06:15 min - 5

Creación de un Sistema de Caché Concurrente en Go
14:29 min - 6

Manejo de Condiciones de Carrera en Go: Implementación de Mutex
08:52 min - 7

Cache concurrente en Go para cálculos intensivos de Fibonacci
16:31 min
Patrones de diseño
- 8

Patrones de Diseño en Programación Orientada a Objetos con Go
04:53 min - 9

Patrón de Diseño Factory en Go: Creación y Uso Práctico
15:17 min - 10

Implementación de Singleton en Go para Conexiones de Base de Datos
08:48 min - 11

Patrón de Diseño Adapter en Go: Implementación Práctica
09:50 min - 12

Patrón de Diseño Observer en Go: Implementación Práctica
11:59 min - 13

Implementación del Patrón de Diseño Strategy en Go
08:53 min
Net
- 14

Escaneo de Puertos TCP con Go: Introducción Básica
07:45 min - 15

Concurrencia en Go: Escáner de Puertos Eficiente y Personalizable
09:16 min - 16

Implementación de NetCAD como Cliente TCP en Go
10:14 min - 17

Construcción de Back End para Servidor de Chat en Go
16:08 min - 18

Implementación de un Servidor de Chat en Go con TCP
13:54 min
Conclusión
Condiciones de Carrera en Programación Concurrente con Go
Resumen
Cuando varias gorutinas acceden al mismo valor de forma simultánea, pueden ocurrir errores silenciosos y difíciles de rastrear. Comprender este problema es fundamental para escribir programas concurrentes seguros, especialmente cuando se trabaja con operaciones sensibles como transacciones financieras.
¿Qué ocurre cuando las gorutinas comparten valores?
En programación concurrente existen dos escenarios principales. El primero es cuando cada gorutina es independiente y no comparte ningún dato con las demás. El segundo, más complejo, es cuando múltiples gorutinas necesitan leer y modificar el mismo valor [0:06]. Este segundo caso es donde aparecen los problemas.
Para ilustrarlo, se plantea un programa financiero con dos operaciones básicas sobre una misma cuenta bancaria: depositar y retirar. Cada operación es manejada por una gorutina diferente, pero todas trabajan sobre el mismo balance.
¿Cómo funcionan las operaciones de depósito y retiro?
La estructura del programa es sencilla [1:12]:
- La función depositar toma el balance actual de la cuenta y le suma el valor depositado.
- La función retirar primero verifica que el monto a retirar sea menor o igual al balance disponible, y luego resta esa cantidad.
En el ejemplo, el balance inicial es de quinientos. Se lanzan dos gorutinas: una deposita doscientos y otra deposita cien [1:38]. Ambas gorutinas leen el mismo valor de balance al iniciar.
¿Qué resultados pueden ocurrir con depósitos concurrentes?
Existen tres posibilidades [1:52]:
- El depósito de cien se ejecuta primero y después el de doscientos.
- El depósito de doscientos se ejecuta primero y luego el de cien.
- Ambos depósitos ocurren al mismo tiempo.
En los dos primeros casos, el resultado es el esperado: un balance final de ochocientos. Pero en el tercer caso, ambas gorutinas leen el balance original de quinientos antes de que la otra escriba su resultado. Una termina con seiscientos y la otra con setecientos. El balance final será uno de esos dos valores, lo que significa que una transacción desaparece [2:43].
¿Qué es una condición de carrera?
Este problema se conoce como condición de carrera (race condition) [3:06]. Ocurre cuando dos o más gorutinas acceden a un recurso compartido sin ningún mecanismo de sincronización, y el resultado depende del orden impredecible en que se ejecutan.
Un segundo ejemplo refuerza el concepto [3:10]. Primero se deposita doscientos, lo que debería llevar el balance a setecientos. Luego se intenta retirar setecientos. La función de retiro verifica que el monto sea menor o igual al balance, pero si la gorutina de retiro lee el balance antes de que el depósito se refleje, verá solo quinientos y el retiro podría fallar o producir un resultado inconsistente [3:30].
Lo más peligroso de las condiciones de carrera es que son muy difíciles de detectar. El programa puede funcionar correctamente la mayoría de las veces y fallar solo bajo ciertas condiciones de tiempo, lo que complica su depuración.
¿Cómo resuelve Go las condiciones de carrera?
Go ofrece herramientas integradas para manejar estos riesgos. Una de ellas es el uso de locks (bloqueos), que permiten que solo una gorutina acceda a un recurso compartido a la vez [3:55]. Mientras una gorutina tiene el lock, las demás esperan hasta que se libere.
Este mecanismo garantiza que:
- Las lecturas y escrituras sobre un valor compartido se realicen de forma atómica.
- No se pierdan transacciones ni se generen estados inconsistentes.
- El programa mantenga la integridad de los datos incluso bajo alta concurrencia.
Identificar y prevenir condiciones de carrera es una habilidad esencial en el desarrollo con Go. Si has trabajado con programas concurrentes, comparte tu experiencia con estos problemas y cómo los has resuelto.