Aula 35 - Tutorial Golang - Tickers

Em Go, tanto Timers quanto Tickers são mecanismos usados para agendar e controlar a execução de tarefas em momentos futuros ou em intervalos regulares. No entanto, eles têm finalidades ligeiramente diferentes: Timers:
  • Um Timer representa um único evento no futuro.
  • Ele é criado com time.NewTimer(duração), onde a "duração" é o período de tempo que o temporizador aguardará antes de disparar.
  • Quando o Timer expira, ele envia um valor para o canal C associado a ele.
  • O Timer pode ser usado para executar uma tarefa única após um determinado intervalo de tempo.
  • Ele pode ser cancelado antes de expirar usando o método Stop().
  • É útil quando você deseja agendar uma única execução no futuro e pode cancelar essa execução se necessário.
Tickers:
  • Um Ticker é semelhante a um Timer, mas dispara repetidamente em intervalos regulares.
  • Ele é criado com time.NewTicker(intervalo), onde o "intervalo" é o período de tempo entre cada disparo.
  • O Ticker envia regularmente valores para o canal C associado a ele, a cada intervalo definido.
  • Os Tickers são ideais para tarefas que precisam ser repetidamente executadas em intervalos fixos.
  • Os Tickers não podem ser cancelados, portanto, eles continuam disparando até que o programa seja interrompido.
Na aula passada, vimos o seguinte código (O último da aula passada!):

package main

import (
	"fmt"
	"time"
)

func notificacao() {
	fmt.Println("Notificação enviada!")
}

func main() {
	// Criando um temporizador para notificação a cada 10 segundos
	temporizador := time.NewTimer(5 * time.Second)

	// Executando a notificação em um loop infinito
	for {
		<-temporizador.C
		notificacao()

		// Reiniciando o temporizador para o próximo intervalo
		temporizador.Reset(5 * time.Second)
	}
}
Esse código simula um comportamento semelhante ao de um Ticker usando um Timer. O código cria um Timer que dispara a cada 5 segundos, executando a função de notificação e em seguida, redefinindo o Timer para o próximo intervalo de 5 segundos. Isso resulta em um loop infinito de notificações a cada 5 segundos, similar ao comportamento de um Ticker. No entanto, há uma diferença importante a ser considerada:
  1. Ticker: O Ticker é uma abstração que encapsula essa lógica de forma mais direta e explícita. Ele foi projetado especificamente para repetir tarefas em intervalos regulares, e é a opção preferida quando você tem essa necessidade.
  2. Timer: O Timer, como está sendo usado no código acima, pode ser uma alternativa quando você precisa de um comportamento mais flexível, como agendar uma tarefa única no futuro com a capacidade de cancelá-la. Nesse exemplo acima, o código está basicamente transformando um Timer em algo que se comporta como um Ticker.
Ambos os métodos são válidos, mas, é importante escolher a abstração que melhor se adapta à intenção do seu código. Se a repetição em intervalos regulares for o objetivo principal, o uso de um Ticker é mais apropriado e também mais legível para que outros desenvolvedores possam ler o seu código no futuro e entender rapidamente.

Exemplo 01

package main

import (
    "fmt"
    "time"
)

func main() {

    // Tickers use a similar mechanism to timers: a
    // channel that is sent values. Here we'll use the
    // `select` builtin on the channel to await the
    // values as they arrive every 1000ms.
    ticker := time.NewTicker(1000 * time.Millisecond)
    done := make(chan bool)

    go func() {
        for {
            select {
                case <- done:
                    return
                case t := <- ticker.C:
                    fmt.Println("Tick at", t)
            }
        }
    }()

    // Tickers can be stopped like timers. Once a ticker
    // is stopped it won't receive any more values on its
    // channel. We'll stop ours after 5000ms.
    time.Sleep(5000 * time.Millisecond)
    ticker.Stop()
    done <- true
    fmt.Println("Ticker stopped")
}

Explicação do exemplo 01

  1. Um Ticker é criado usando time.NewTicker(1000 * time.Millisecond). Isso cria um Ticker que enviará valores para o canal C a cada 1000 milissegundos.
  2. É criado um canal doneque será usado para sinalizar quando o Ticker foi parado.
  3. Uma goroutine é iniciada usando go func() {...}. Esta goroutine lida com o Ticker e o canal de sinalização. No loop for, usamos um selectpara aguardar valores nos canais doneou ticker.C. Se recebermos um valor do canal done, a goroutine é encerrada. Se recebermos um valor do canal ticker.C, significa que o Ticker disparou e imprimimos a mensagem "Tick at" seguida do tempo atual.
  4. time.Sleep(5000 * time.Millisecond) aguarda por 5000 milissegundos (ou 5 segundos) antes de continuar. Isso é feito para simular o tempo de execução do Ticker.
  5. ticker.Stop() é chamado para parar o Ticker. Isso significa que ele não enviará mais valores para o canal C.
  6. done <- true é usado para enviar um sinal para a goroutine do Ticker, indicando que ela deve parar.
  7. Por fim, uma mensagem "Ticker stopped" é impressa para indicar que o Ticker foi parado.
Em resumo, o código cria um Ticker que dispara a cada 1000ms, executa uma tarefa quando o Ticker dispara e depois de um tempo especificado, para o Ticker e encerra a goroutine associada a ele. Isso demonstra de maneira prática como usar e parar um Ticker em Go.

Exemplo 02 - Envio de E-mails Periódicos

package main

import (
	"fmt"
	"time"
)

func enviarEmail() {
	fmt.Println("Enviando e-mail...")
}

func main() {
	ticker := time.NewTicker(1 * time.Hour)

	for range ticker.C {
		enviarEmail()
	}
}

Explicação do exemplo 02 - Envio de E-mails Periódicos

Neste exemplo, criamos um Ticker que dispara a cada hora. Na função main, iniciamos um loop que aguarda os disparos do Ticker. A cada disparo, a função enviarEmail() é chamada, simulando o envio de um e-mail periódico.

Exemplo 03 - Exibição de Relógio Digital


package main

import (
	"fmt"
	"time"
)

func exibirRelogio() {
	fmt.Println("Horário atual:", time.Now().Format("15:04:05"))
}

func main() {
	ticker := time.NewTicker(1 * time.Second)

	for range ticker.C {
		exibirRelogio()
	}
}

Explicação do exemplo 03 - Exibição de Relógio Digital

Neste exemplo, usamos um Ticker para atualizar e exibir o horário atual a cada segundo. A função exibirRelogio() formata a hora atual no formato HH:MM:SS e a imprime a cada disparo do Ticker.

Exemplo 04 - Atualização de Dados Online


package main

import (
	"fmt"
	"time"
)

func atualizarDadosOnline() {
	fmt.Println("Atualizando dados online...")
}

func main() {
	ticker := time.NewTicker(30 * time.Second)

	go func() {
		for range ticker.C {
			atualizarDadosOnline()
		}
	}()

	// Simula o tempo para observar as atualizações
	time.Sleep(5 * time.Minute)
	ticker.Stop()
	fmt.Println("Atualizações online interrompidas")
}

Explicação do exemplo 04 - Atualização de Dados Online

Neste exemplo, usamos um Ticker para simular a atualização de dados online a cada 30 segundos. Iniciamos uma goroutine para aguardar os disparos do Ticker e chamar a função atualizarDadosOnline(). Após 5 minutos, o Ticker é interrompido, cessando as atualizações online.

Exemplo 05 - Leitura de Sensores em Intervalos Regulares


package main

import (
	"fmt"
	"time"
)

func lerSensor() {
	fmt.Println("Lendo sensor...")
}

func main() {
	ticker := time.NewTicker(10 * time.Minute)

	go func() {
		for range ticker.C {
			lerSensor()
		}
	}()

	// Simula o tempo para observar a leitura dos sensores
	time.Sleep(1 * time.Hour)
	ticker.Stop()
	fmt.Println("Leitura de sensores interrompida")
}
Neste exemplo, usamos um Ticker para simular a leitura de sensores a cada 10 minutos. Uma goroutine aguarda os disparos do Ticker e chama a função lerSensor(). Após 1 hora, o Ticker é interrompido, cessando a leitura dos sensores. Espero que esses exemplos e explicações forneçam uma compreensão clara dos Tickers e de como eles podem ser usados em casos de uso práticos em Go.

Eu fico por aqui e agradeço a você pela audiência.

Até mais. :)

Página principal do blog

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Obrigado e bons estudos. ;)