Patrones de concurrencia
Introducción a los patrones de concurrencia
Los patrones de concurrencia proporcionan enfoques estructurados para resolver desafíos complejos de programación concurrente utilizando canales (channels) en Golang.
Patrones de concurrencia comunes de canales
1. Patrón de grupo de trabajadores (Worker Pool Pattern)
graph LR
A[Job Queue] --> B[Worker Pool]
B --> C[Result Channel]
func workerPool(jobs <-chan int, results chan<- int) {
for job := range jobs {
results <- processJob(job)
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Create worker pool
for w := 1; w <= 3; w++ {
go workerPool(jobs, results)
}
// Send jobs
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// Collect results
for a := 1; a <= 5; a++ {
<-results
}
}
2. Patrón de expansión (Fan-Out) y consolidación (Fan-In)
Patrón |
Descripción |
Caso de uso |
Fan-Out |
Un solo canal distribuido a múltiples trabajadores |
Procesamiento paralelo |
Fan-In |
Varios canales consolidados en un solo canal |
Agregación de resultados |
func fanOutFanIn() {
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
// Fan-Out
go func() {
for i := 0; i < 10; i++ {
ch1 <- i
ch2 <- i
}
close(ch1)
close(ch2)
}()
// Fan-In
go func() {
for {
select {
case v, ok := <-ch1:
if !ok {
ch1 = nil
}
ch3 <- v
case v, ok := <-ch2:
if !ok {
ch2 = nil
}
ch3 <- v
}
if ch1 == nil && ch2 == nil {
close(ch3)
return
}
}
}()
}
3. Patrón de semáforo (Semaphore Pattern)
type Semaphore struct {
semaChan chan struct{}
}
func NewSemaphore(max int) *Semaphore {
return &Semaphore{
semaChan: make(chan struct{}, max),
}
}
func (s *Semaphore) Acquire() {
s.semaChan <- struct{}{}
}
func (s *Semaphore) Release() {
<-s.semaChan
}
Patrones de concurrencia avanzados
Patrón de tubería (Pipeline Pattern)
graph LR
A[Stage 1] --> B[Stage 2]
B --> C[Stage 3]
func generateNumbers(max int) <-chan int {
ch := make(chan int)
go func() {
for i := 1; i <= max; i++ {
ch <- i
}
close(ch)
}()
return ch
}
func squareNumbers(input <-chan int) <-chan int {
ch := make(chan int)
go func() {
for n := range input {
ch <- n * n
}
close(ch)
}()
return ch
}
Mejores prácticas de patrones de concurrencia
- Utilizar canales para la comunicación
- Evitar el uso de memoria compartida
- Diseñar para la previsibilidad
- Manejar adecuadamente el cierre de los canales
Conocimientos sobre concurrencia de LabEx
En LabEx, recomendamos practicar estos patrones a través de ejercicios de complejidad progresiva para dominar las técnicas de programación concurrente.
Conclusión
Los patrones de concurrencia efectivos permiten:
- Un diseño de sistema escalable
- Una utilización eficiente de recursos
- Código concurrente limpio y mantenible