Timers in Racket

#lang racket

(require racket/async-channel)

(define (main)
  ; Timers represent a single event in the future. You
  ; tell the timer how long you want to wait, and it
  ; provides a channel that will be notified at that
  ; time. This timer will wait 2 seconds.
  (define timer1 (make-async-channel))
  (thread (lambda ()
            (sleep 2)
            (async-channel-put timer1 'fired)))

  ; The (async-channel-get timer1) blocks on the timer's channel
  ; until it receives a value indicating that the timer fired.
  (async-channel-get timer1)
  (printf "Timer 1 fired\n")

  ; If you just wanted to wait, you could have used
  ; (sleep). One reason a timer may be useful is
  ; that you can cancel the timer before it fires.
  ; Here's an example of that.
  (define timer2 (make-async-channel))
  (define timer2-thread
    (thread (lambda ()
              (sleep 1)
              (async-channel-put timer2 'fired)
              (printf "Timer 2 fired\n"))))

  (sleep 0.5)
  (kill-thread timer2-thread)
  (printf "Timer 2 stopped\n")

  ; Give the timer2 enough time to fire, if it ever
  ; was going to, to show it is in fact stopped.
  (sleep 2))

(main)

This program demonstrates the use of timers in Racket. Racket doesn’t have built-in timer objects like Go, so we simulate them using threads and async channels.

Here’s how it works:

  1. We create a timer (timer1) that waits for 2 seconds. This is done by creating an async channel and a thread that sleeps for 2 seconds before putting a value into the channel.

  2. We wait for the timer to fire by getting a value from the async channel. This blocks until the timer fires.

  3. We then create a second timer (timer2) that’s supposed to fire after 1 second. However, we stop this timer before it has a chance to fire.

  4. To stop the timer, we kill the thread that’s running it. In a real-world scenario, you might want to use a more graceful way to stop a thread.

  5. Finally, we sleep for 2 seconds to give timer2 enough time to fire if it was going to, demonstrating that it has indeed been stopped.

To run the program, save it as timers.rkt and use the racket command:

$ racket timers.rkt
Timer 1 fired
Timer 2 stopped

The output shows that the first timer fired after about 2 seconds, but the second timer was stopped before it had a chance to fire.

This example demonstrates how to create simple timers in Racket and how to cancel them. While the implementation differs from Go due to language differences, the core concepts of creating timed events and being able to cancel them are preserved.