Aula 38 - Tutorial Golang - Análise de Dados em Tempo Real
WorkerPools e WaitGroups
O código é um exemplo que simula a
coleta de dados de
sensores em
tempo real, processando esses dados em um
pool de workers e controlando o término da simulação.
Esse sensor simulado, gera números float aleatórios, que podemos pensar que seja a captação de dado de algum sensor como: sensores ambientais(barômetros, fotômetros, termômetros), sensores de movimento(acelerômetros, sensores de gravidade, giroscópios e sensores vetoriais de rotação), sensores de posição(orientação e magnetômetros)...
Podemos imaginar um caso como esse, como um exemplo de uso de micro serviço em um ecossistema de software maior.
Essa simulação de coleta de dados é uma parte de um possível sistema maior, onde a coleta e o processamento de dados de sensores são apenas uma das muitas tarefas ou serviços que podem fazer parte de um sistema mais amplo.
Em um ecossistema de software real, esse micro serviço poderia ser uma parte de um sistema de monitoramento, análise de dados em tempo real, ou qualquer aplicação que envolva a coleta e processamento contínuo de dados de sensores.
Golang, a Escolha Certa!
O uso do
Go nesse exemplo de uso, oferece uma vantagem significativa devido à sua eficiência na
programação distribuída e na manipulação de
concorrência.
Go foi projetado com a capacidade de criar
sistemas concorrentes e
distribuídos de forma eficaz, tornando-o uma escolha ideal para cenários onde a coleta e o processamento de dados em tempo real são essenciais.
Sua capacidade de lidar com
concorrência por meio de
goroutines e canais torna a criação de
micro serviços e a coordenação entre diferentes partes de um
sistema distribuído uma tarefa simplificada.
Isso faz do
Go uma linguagem de programação adequada para desenvolvedores que desejam criar sistemas eficientes e responsivos que se beneficiem da
programação distribuída e do
paralelismo de forma
transparente.
Analisando o Código
O
const declara constantes, incluindo o
número de sensores,
intervalo de geração de dados,
número de workers e
duração da simulação.
O
var wg sync.WaitGroup cria uma variável do tipo
sync.WaitGroup para rastrear
goroutines ativas e aguardar seu término.
O
sensorData := make(chan float64, numSensors) cria um canal chamado
sensorData para transmitir leituras de sensores para os
workers, com um buffer para acomodar leituras pendentes.
O
done := make(chan struct{}) cria um canal done para sinalizar o término da simulação.
O bloco de inicialização do pool de workers começa com um
loop que
cria goroutines para os
workers.
Cada
worker é uma
goroutine que executa a função worker e recebe o
canal sensorData para processar dados.
Outro
loop cria
goroutines separadas que simulam a
geração de dados de sensores.
Cada
goroutine executa a função
simulateSensor() e gera dados aleatórios, que são enviados para o
canal sensorData.
Uma
goroutine anônima é usada para aguardar a duração da simulação com
time.Sleep(simulationDuration).
Quando a simulação atinge a duração especificada, a
goroutine fecha o
canal done, indicando o término da simulação.
Outra
goroutine anônima aguarda a conclusão de todas as
goroutines do
pool de
workers usando
wg.Wait().
Quando todas as
goroutines do
pool terminam, a
goroutine fecha o
canal sensorData, indicando que não há mais dados para processar.
O programa principal aguarda a conclusão de ambas as
goroutines, usando
<-done e em seguida, imprime "
Coleta de dados concluída" para indicar que a simulação terminou antes de encerrar a execução do programa.
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
const (
numSensors = 5
dataInterval = 1 * time.Second
numWorkers = 3
simulationDuration = 5 * time.Second // Defina a duração da simulação
)
func main() {
var wg sync.WaitGroup
sensorData := make(chan float64, numSensors)
done := make(chan struct{}) // Canal para sinalizar o término da simulação
// Inicializa o worker pool
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(sensorData, &wg)
}
// Simula a coleta de dados de sensores em goroutines separadas
for i := 0; i < numSensors; i++ {
wg.Add(1)
go simulateSensor(i, sensorData, &wg)
}
// Aguarde a duração da simulação
go func() {
time.Sleep(simulationDuration)
close(done)
}()
// Aguarde a conclusão de todas as goroutines
go func() {
wg.Wait()
close(sensorData)
}()
// Espere que ambas as goroutines terminem
<-done
fmt.Println("Coleta de dados concluída.")
}
func worker(sensorData <-chan float64, wg *sync.WaitGroup) {
defer wg.Done()
for data := range sensorData {
// Processa os dados do sensor aqui (exemplo: salvar em um banco de dados, realizar cálculos, etc.)
fmt.Printf("Dado do sensor: %.2f\n", data)
}
}
func simulateSensor(id int, sensorData chan<- float64, wg *sync.WaitGroup) {
defer wg.Done()
rand.Seed(time.Now().UnixNano())
// Loop infinito
for {
data := rand.Float64() * 100.0 // Simula um dado de sensor
sensorData <- data
time.Sleep(dataInterval)
}
}
Resumo
- Configuração de constantes, como o número de sensores, intervalo de geração de dados, número de workers e duração da simulação.
- Inicialização de um canal para enviar leituras de sensores para os workers e um canal para sinalizar o término da simulação.
- Inicialização do pool de workers em goroutines que processam os dados dos sensores.
- Simulação da coleta de dados de sensores em goroutines separadas que geram dados aleatórios e os enviam para o canal.
- Uma goroutine aguarda a duração da simulação e fecha o canal de término quando o tempo limite é atingido.
- Outra goroutine aguarda a conclusão de todas as goroutines do pool de workers e, em seguida, fecha o canal de dados dos sensores.
- O programa principal aguarda a conclusão de ambas as goroutines de término e, em seguida, imprime "Coleta de dados concluída" e encerra o programa.
Eu fico por aqui.
Até a próxima. ;)
Meus links de afiliados:
Obrigado e bons estudos. ;)