Cache concurrente en Go para cálculos intensivos de Fibonacci
Clase 7 de 19 • Curso de Go Avanzado: Concurrencia y Patrones de Diseño
Contenido del curso
Concurrencia
- 2

Condiciones de Carrera en Programación Concurrente con Go
04:52 min - 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
Viendo ahora
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:51 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
¿Cómo resolver problemas de concurrencia en un sistema de caché para la serie de Fibonacci?
La implementación de un sistema de caché eficiente para la serie de Fibonacci puede parecer simple en escenarios básicos, pero se vuelve un desafío cuando se introducen procesos concurrentes. Imagínate una situación donde varios procesos simultáneos solicitan el cálculo de valores de Fibonacci para números grandes que, de no estar bien gestionados, podrían sobrecargar tu sistema. En este contexto, es esencial desarrollar un sistema que no solo gestione la caché eficientemente, sino que también identifique y gestione las operaciones que están en progreso y aquellas que ya están listas para entrega. En esta guía, veremos cómo implementar un sistema de caché con manejo de procesos concurrentes, tomando como referencia el lenguaje de programación Go.
¿Cómo simular un cálculo intensivo de Fibonacci?
Para simular un cálculo intensivo, se puede emplear una función que representa un tiempo de ejecución prolongado. La función Fibonacci no solo debe calcular el valor, sino también emular tiempo de procesamiento significativo:
func calcularFibonacci(n int) int {
fmt.Printf("Calculando Fibonacci costoso para %d\n", n)
time.Sleep(5 * time.Second) // Simula un cálculo largo
return n
}
¿Cómo definir estructuras y mapas para gestionar trabajos en proceso?
Para manejar múltiples procesos concurrentes, es crucial definir estructuras y mapas que gestionen qué trabajos se están procesando actualmente y cuáles están esperando una respuesta:
type Servicio struct {
enProgreso map[int]bool
enEspera map[int][]chan int
mu sync.RWMutex // candado para evitar condiciones de carrera
}
enProgreso: Mapa que indica si un trabajo está en proceso.enEspera: Mapa que almacena canales de respuesta para trabajos que esperan resultados.
¿Cómo implementar la función de trabajo para gestionar procesos concurrentes?
El método trabajar se encarga de manejar las operaciones concurrentes. Comprueba si un trabajo está en progreso y actúa consecuentemente:
func (s *Servicio) trabajar(trabajo int) {
s.mu.RLock()
if s.enProgreso[trabajo] {
// Si está en progreso, agrega el trabajador al mapa de espera
ch := make(chan int, 1)
s.mu.RUnlock()
// Operaciones que involucran bloqueo total
s.mu.Lock()
s.enEspera[trabajo] = append(s.enEspera[trabajo], ch)
s.mu.Unlock()
// Espera la respuesta
respuesta := <-ch
fmt.Printf("Respuesta recibida: %d\n", respuesta)
return
}
s.mu.RUnlock()
// Si no está en progreso, calcúlelo y notifique a los trabajadores
s.mu.Lock()
s.enProgreso[trabajo] = true
s.mu.Unlock()
fmt.Printf("Calculando Fibonacci para %d\n", trabajo)
resultado := calcularFibonacci(trabajo)
s.mu.Lock()
for _, ch := range s.enEspera[trabajo] {
ch <- resultado
close(ch)
}
s.enProgreso[trabajo] = false
s.enEspera[trabajo] = nil
s.mu.Unlock()
}
¿Cómo instanciar el servicio y gestionar trabajos concurrentemente?
Para poner a prueba nuestro sistema, definimos un conjunto de trabajos y los procesamos concurrentemente utilizando sync.WaitGroup:
func main() {
servicio := &Servicio{
enProgreso: make(map[int]bool),
enEspera: make(map[int][]chan int),
}
trabajos := []int{3, 4, 5, 5, 4, 8, 8, 8}
wg := &sync.WaitGroup{}
wg.Add(len(trabajos))
for _, trabajo := range trabajos {
go func(trabajo int) {
defer wg.Done()
servicio.trabajar(trabajo)
}(trabajo)
}
wg.Wait()
}
Con esta implementación, hemos creado un sistema de caché que maneja de forma efectiva procesos concurrentes al gestionar trabajos en progreso y esperando resultados. Te animo a implementar tus propias mejoras y explorar combinaciones con otras técnicas de caché para crear una solución aún más robusta. ¡Sigue avanzando y experimentando con nuevas ideas!