Dwi Wahyudi

Senior Software Engineer (Ruby, Golang, Java)


In this post we will write some code using Golang’s tickers, a utility to repeat tasks.

Overview

Previously we have demonstrated usages of timers: Golang Timers.

Tickers and timers are different, a timer instance will trigger only once, while a ticker instance can trigger multiple times.

Let say we have a simple app here to remind us the prices of items.

func priceReminderInterval() map[string]int {
	reminderInterval := map[string]int{
		"gold":   1,
		"timber": 3,
		"wood":   5,
		"iron":   2,
	}
	return reminderInterval
}

We will be reminded of gold price every 1 second, timber every 3 seconds, and so on.

And here’s how we will remind ourselves, via a ticker channel:

func receiveTicker(item string, ticker *time.Ticker) {
	for range ticker.C {
		price := rand.Intn(100)

		fmt.Println(item + ", price " + strconv.Itoa(price))
	}
}

In real world, such price will be supplied by other data sources, but here for demonstration purpose, let’s just generate a random price.

Let’s now create a ticker for reminding us of timber price every 3 seconds, pretty straightforward, use time.NewTicker() function, and supply it with interval of the ticker.

func singleTickerDemo() {
	item := "timber"
	reminderInterval := priceReminderInterval()[item]

	ticker := time.NewTicker(time.Duration(reminderInterval) * time.Second)

	receiveTicker(item, ticker)
}

When running this, each price will appear every 3 seconds.

Multiple Instances of Tickers

We can have multiple tickers at the same time, let say we want to monitor all of those items’ prices, each interval needs its own goroutine so not to block each other.

func demoMultipleTickers() {
	for item, reminderInterval := range priceReminderInterval() {
		reminderTicker := time.NewTicker(time.Duration(reminderInterval) * time.Second)

		go receiveTicker(item, reminderTicker)
	}
}

When running this, we will see that each item price will appear at different interval. Gold every second, timber every 3 seconds, wood every 5 seconds and iron every 2 seconds. Each has its own ticker instance, in other words, we have 4 tickers instances at the same time.

Stopping Tickers

If we want to stop a ticker, we can just call Stop() method on it.

func stopTicker(item string, ticker *time.Ticker) {
	time.Sleep(8 * time.Second)

	fmt.Println("Timer stop for", item)
	ticker.Stop()
}

This function receives a ticker instance, after 8 seconds, the ticker will be stopped, it won’t tick anymore, thus we will no longer receive price reminder anymore, ticker will stop sending to ticker.C channel.

Let’s apply this to our code, make sure to stop each ticker in other goroutines as well.

func demoMultipleTickersWithStop() {
	for item, reminderInterval := range priceReminderInterval() {
		reminderTicker := time.NewTicker(time.Duration(reminderInterval) * time.Second)

		go stopTicker(item, reminderTicker)
		go receiveTicker(item, reminderTicker)
	}
}

When we run this, we will notice that after 8 seconds, all of tickers will no longer run.

Here’s the code of the demonstration: https://github.com/dwahyudi/golang-tickers