Resumen - Worker Pool
Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy — lección 66 de 107.
Desafío
Fácil¡Vamos a construir un sistema de procesamiento de tareas utilizando el patrón de pool de trabajadores (worker pool)! Crearás un grupo de trabajadores que procesan tareas computacionales de forma concurrente, demostrando cómo los canales, las goroutines y los WaitGroups trabajan juntos para manejar cargas de trabajo de manera eficiente.
Organizarás tu código en dos archivos:
pool.go: Define los componentes y la lógica de tu pool de trabajadores.Crea una estructura
Taskcon los camposID(int) yValue(int) que representan el trabajo a realizar.Crea una estructura
Resultcon los camposTaskID(int) yComputed(int) que representan el trabajo completado.Implementa una función
Workerque reciba un ID de trabajador (int), un canal de solo recepción de tareas (<-chan Task), un canal de solo envío para resultados (chan<- Result) y un puntero a unsync.WaitGroup. Cada trabajador debe:- Usar
defer wg.Done()para señalar la finalización - Iterar (range) sobre el canal de tareas para procesar cada tarea
- Para cada tarea, calcular el cuadrado del
Valuede la tarea - Enviar un
Resultcon elTaskIDy el cuadrado calculado
Implementa una función
RunPoolque reciba el número de trabajadores (int) y una rebanada (slice) de tareas. Esta función debe:- Crear canales con búfer para tareas y resultados (usa el número de tareas como tamaño del búfer)
- Iniciar el número especificado de trabajadores como goroutines
- Enviar todas las tareas al canal de tareas y luego cerrarlo
- Usar una goroutine con el
WaitGrouppara cerrar el canal de resultados después de que todos los trabajadores terminen - Recolectar todos los resultados en un slice y devolverlo
- Usar
main.go: Lee la entrada y coordina el pool de trabajadores.Lee el número de trabajadores, luego el número de tareas. Para cada tarea, lee su ID y su valor. Llama a
RunPoolcon los trabajadores y las tareas, luego imprime cada resultado en el formato:Task [TaskID]: [Computed]Imprime los resultados ordenados por
TaskIDen orden ascendente.
Se proporcionarán las siguientes entradas:
- Línea 1: Número de trabajadores (entero)
- Línea 2: Número de tareas (entero)
- Líneas siguientes: Para cada tarea, dos líneas - el ID de la tarea (entero), luego su valor (entero)
Por ejemplo, dado:
2
4
1
3
2
5
3
2
4
7Tu salida debería ser:
Task 1: 9
Task 2: 25
Task 3: 4
Task 4: 49Los trabajadores procesan las tareas de forma concurrente (3 al cuadrado es 9, 5 al cuadrado es 25, etc.), y los resultados se recolectan y muestran en orden por el ID de la tarea. Con 2 trabajadores manejando 4 tareas, el trabajo se distribuye a través del pool de manera eficiente.
Pruébalo tú mismo
package main
import (
"fmt"
"sort"
)
func main() {
// Leer el número de trabajadores
var numWorkers int
fmt.Scanln(&numWorkers)
// Leer el número de tareas
var numTasks int
fmt.Scanln(&numTasks)
// Leer tareas
tasks := make([]Task, numTasks)
for i := 0; i < numTasks; i++ {
var id, value int
fmt.Scanln(&id)
fmt.Scanln(&value)
tasks[i] = Task{ID: id, Value: value}
}
// TODO: Llamar a RunPool con trabajadores y tareas
// TODO: Ordenar los resultados por TaskID en orden ascendente
// TODO: Imprimir cada resultado en el formato: Task [TaskID]: [Computed]
}
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO en Go
Archivos externosEspacio de trabajo y módulos de GoPaquetes e importacionesNombres exportados vs. no exportadosIntroducción a la POO en GoStructs como clasesDefinición de métodos en structsReceptores de puntero vs. de valorInicialización de structsFunciones constructorasResumen - Calculadora simple4Interfaces
Introducción a las interfacesImplementación implícitaLa interfaz como contratoInterfaz vacía (any)Type AssertionType SwitchComposición de interfacesInterfaces Stringer y ErrorResumen: Calculadora de figuras7Encapsulamiento
Campos exportados vs. no exportadosEncapsulamiento a nivel de paqueteMétodos Getter y SetterOcultamiento de información en GoResumen - Registros de estudiantes10Genéricos (Go 1.18+)
Introducción a los GenéricosParámetros de tipoRestricciones de tipoStructs genéricosSolución alternativa para métodos genéricosResumen - Colección genérica13Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón Abstract FactoryPatrón ObserverPatrón Strategy2Inmersión profunda en Tipos y Structs
Tipos básicos y compuestosDefiniciones de tipos personalizadosEtiquetas de StructsStructs anónimosStructs anidadosValores cero y por defectoRepaso - Libreta de contactos5Composición sobre herencia
Por qué Go no tiene herenciaConceptos básicos de incrustación de structsPromoción de métodosIncrustación de múltiples structsIncrustación vs AgregaciónShadowing de métodos incrustadosResumen - Jerarquía de empleados8Manejo de Errores y OOP
La interfaz errorTipos de errores personalizadosEnvoltura de errores (fmt.Errorf)Errores centinelaerrors.Is() y errors.As()Panic, Defer y RecoverResumen - Analizador de archivos3Punteros y Memoria
Fundamentos de punteros en GoPunteros a StructsPaso por valor vs referenciaLa función new()Garbage Collection en GoResumen - Constructor de Linked List6Polimorfismo en Go
Polimorfismo mediante interfacesDuck Typing en GoReglas de satisfacción de interfacesColecciones polimórficasInyección de dependenciasResumen - Procesador de pagos9Concurrencia y POO
Fundamentos de GoroutinesChannels y comunicaciónChannels con buffer vs. sin bufferSentencia Selectsync.Mutex y sync.RWMutexsync.WaitGroupDiseño de estructuras Thread-SafeResumen - Worker Pool