Recapitulação - Worker Pool
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 66 de 107.
Desafio
FácilVamos construir um sistema de processamento de tarefas usando o padrão worker pool! Você criará um pool de trabalhadores (workers) que processam tarefas computacionais de forma concorrente, demonstrando como canais, goroutines e WaitGroups trabalham juntos para lidar com cargas de trabalho de forma eficiente.
Você organizará seu código em dois arquivos:
pool.go: Defina os componentes e a lógica do seu worker pool.Crie uma struct
Taskcom os camposID(int) eValue(int) representando o trabalho a ser feito.Crie uma struct
Resultcom os camposTaskID(int) eComputed(int) representando o trabalho concluído.Implemente uma função
Workerque recebe um ID de worker (int), um canal de tarefas apenas para recebimento (<-chan Task), um canal para resultados apenas para envio (chan<- Result) e um ponteiro para umsync.WaitGroup. Cada worker deve:- Usar
defer wg.Done()para sinalizar a conclusão - Percorrer (range) o canal de tarefas para processar cada tarefa
- Para cada tarefa, calcular o quadrado do campo Value da tarefa
- Enviar um Result com o TaskID e o quadrado calculado
Implemente uma função
RunPoolque recebe o número de workers (int) e um slice de tarefas. Esta função deve:- Criar canais com buffer para tarefas e resultados (use o número de tarefas como o tamanho do buffer)
- Iniciar o número especificado de workers como goroutines
- Enviar todas as tarefas para o canal de tarefas e, em seguida, fechá-lo
- Usar uma goroutine com o WaitGroup para fechar o canal de resultados após todos os workers terminarem
- Coletar todos os resultados em um slice e retorná-lo
- Usar
main.go: Leia a entrada e coordene o worker pool.Leia o número de workers e, em seguida, o número de tarefas. Para cada tarefa, leia seu ID e valor. Chame
RunPoolcom os workers e as tarefas, depois imprima cada resultado no formato:Task [TaskID]: [Computed]Imprima os resultados ordenados pelo TaskID em ordem crescente.
As seguintes entradas serão fornecidas:
- Linha 1: Número de workers (inteiro)
- Linha 2: Número de tarefas (inteiro)
- Linhas seguintes: Para cada tarefa, duas linhas - o ID da tarefa (inteiro) e, em seguida, seu valor (inteiro)
Por exemplo, dado:
2
4
1
3
2
5
3
2
4
7Sua saída deve ser:
Task 1: 9
Task 2: 25
Task 3: 4
Task 4: 49Os workers processam as tarefas de forma concorrente (3 ao quadrado é 9, 5 ao quadrado é 25, etc.), e os resultados são coletados e exibidos em ordem pelo ID da tarefa. Com 2 workers lidando com 4 tarefas, o trabalho é distribuído pelo pool de forma eficiente.
Experimente você mesmo
package main
import (
"fmt"
"sort"
)
func main() {
// Ler número de trabalhadores
var numWorkers int
fmt.Scanln(&numWorkers)
// Ler número de tarefas
var numTasks int
fmt.Scanln(&numTasks)
// Ler tarefas
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: Chamar RunPool com trabalhadores e tarefas
// TODO: Ordenar resultados por TaskID em ordem crescente
// TODO: Imprimir cada resultado no formato: Task [TaskID]: [Computed]
}
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosGo Workspace e MódulosPacotes e ImportaçõesNomes Exportados vs Não ExportadosIntrodução a OOP em GoStructs como ClassesDefinindo Métodos em StructsRecebedores de Ponteiro vs ValorInicialização de StructsFunções ConstrutorasRecapitulação - Calculadora Simples4Interfaces
Introdução a InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Type AssertionType SwitchComposição de InterfacesInterfaces Stringer & ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs Não ExportadosEncapsulamento em Nível de PacoteMétodos Getter e SetterOcultação de Informação em GoRecapitulação - Registros de Estudantes10Generics (Go 1.18+)
Introdução a GenericsParâmetros de TipoRestrições de TipoStructs GenéricasSolução Alternativa para Métodos GenéricosRecapitulação - Coleção Genérica2Mergulho Profundo em Tipos e Structs
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosStruct TagsStructs AnônimasStructs AninhadasZero Values e PadrõesRecapitulação - Agenda de Contatos5Composição em vez de Herança
Por que Go não possui HerançaFundamentos de Incorporação de StructsPromoção de MétodosIncorporando Múltiplas StructsIncorporação vs AgregaçãoShadowing de Métodos IncorporadosRecapitulação - Hierarquia de Funcionários8Tratamento de Erros e OOP
A Interface errorTipos de Erro PersonalizadosError Wrapping (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - File Parser3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs ReferênciaA Função new()Garbage Collection em GoRecapitulação - Construtor de Lista Encadeada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfaceColeções PolimórficasInjeção de DependênciaRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e ComunicaçãoCanais com Buffer vs. Sem BufferInstrução Selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de Structs Thread-SafeRecapitulação - Worker Pool