Revisã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 criar um sistema de processamento de tarefas usando o padrão de pool de workers! Você criará um pool de workers que processam tarefas computacionais simultaneamente, 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 pool de workers.Crie uma struct
Taskcom camposID(int) eValue(int) representando o trabalho a ser realizado.Crie uma struct
Resultcom camposTaskID(int) eComputed(int) representando o trabalho concluído.Implemente uma função
Workerque receba um ID de worker (int), um canal somente para recebimento de tarefas (<-chan Task), um canal somente para envio de resultados (chan<- Result) e um ponteiro para umsync.WaitGroup. Cada worker deve:- Usar
defer wg.Done()para sinalizar a conclusão - Percorrer o canal de tarefas para processar cada tarefa
- Para cada tarefa, calcular o quadrado do Value da tarefa
- Enviar um Result com o TaskID e o quadrado calculado
Implemente uma função
RunPoolque receba o número de workers (int) e uma fatia de tarefas. Essa função deve:- Criar canais com buffer para tarefas e resultados (use o número de tarefas como 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 depois que todos os workers terminarem
- Coletar todos os resultados em uma fatia e retorná-la
- Usar
main.go: Leia a entrada e coordene o pool de workers.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 e, em seguida, imprima cada resultado no formato:Task [TaskID]: [Computed]Imprima os resultados ordenados por 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, considerando:
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 simultaneamente (3 ao quadrado é 9, 5 ao quadrado é 25 etc.), e os resultados são coletados e exibidos na ordem do ID da tarefa. Com 2 workers lidando com 4 tarefas, o trabalho é distribuído de forma eficiente pelo pool.
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 ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online