Closing Channels in Racket

#lang racket

(require racket/channel)

; In this example we'll use a `jobs` channel to communicate work to be done 
; from the main thread to a worker thread. When we have no more jobs for
; the worker we'll close the `jobs` channel.

(define (main)
  (define jobs (make-channel 5))
  (define done (make-channel))

  ; Here's the worker thread. It repeatedly receives from `jobs` with 
  ; `(channel-try-get jobs)`. This function returns two values: the received 
  ; value and a boolean indicating whether the receive was successful.
  ; We use this to notify on `done` when we've worked all our jobs.
  (thread
   (lambda ()
     (let loop ()
       (define-values (job more) (channel-try-get jobs))
       (cond
         [more
          (printf "received job ~a\n" job)
          (loop)]
         [else
          (printf "received all jobs\n")
          (channel-put done #t)]))))

  ; This sends 3 jobs to the worker over the `jobs` channel, then closes it.
  (for ([j (in-range 1 4)])
    (channel-put jobs j)
    (printf "sent job ~a\n" j))
  (channel-close jobs)
  (printf "sent all jobs\n")

  ; We await the worker using the synchronization approach we saw earlier.
  (channel-get done)

  ; Reading from a closed channel succeeds immediately, returning #f.
  ; The optional second return value is #t if the value received was 
  ; delivered by a successful send operation to the channel, or #f if 
  ; the channel is closed and empty.
  (define-values (_ ok) (channel-try-get jobs))
  (printf "received more jobs: ~a\n" ok))

(main)

To run this program, save it as closing-channels.rkt and execute it using Racket:

$ racket closing-channels.rkt
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: #f

In this Racket version, we use the racket/channel module to work with channels, which are similar to Go’s channels. The make-channel function creates a new channel, and channel-put and channel-get are used to send and receive values respectively.

Instead of goroutines, Racket uses threads. The thread function starts a new thread with the given function.

The channel-try-get function is used to receive from a channel, returning two values: the received value and a boolean indicating whether the receive was successful. This is similar to the two-value form of channel receive in Go.

Closing a channel in Racket is done with channel-close. After a channel is closed, channel-try-get will return #f for both values.

The concept of closing channels in Racket is similar to Go, allowing us to signal that no more values will be sent on the channel.