Select in Clojure

In Clojure, we can use core.async to achieve similar functionality to select. The core.async library provides channels and the go macro for concurrent operations.

(ns select-example
  (:require [clojure.core.async :as async :refer [>! <! go chan alts! timeout]]))

(defn main []
  ; For our example we'll select across two channels.
  (let [c1 (chan)
        c2 (chan)]
    
    ; Each channel will receive a value after some amount
    ; of time, to simulate e.g. blocking RPC operations
    ; executing in concurrent threads.
    (go
      (<! (timeout 1000))
      (>! c1 "one"))
    (go
      (<! (timeout 2000))
      (>! c2 "two"))
    
    ; We'll use alts! to await both of these values
    ; simultaneously, printing each one as it arrives.
    (dotimes [_ 2]
      (let [[val channel] (async/<!! (async/alts! [c1 c2]))]
        (println "received" val)))))

(main)

In this Clojure version:

  1. We use core.async library which provides similar concurrency primitives to Go.
  2. Instead of select, we use alts! which allows us to wait on multiple channels.
  3. The go macro is used to create lightweight processes (similar to goroutines).
  4. We use chan to create channels.
  5. >! is used to put a value onto a channel, and <! is used to take a value from a channel.
  6. timeout is used to simulate delay.

To run this program:

$ lein run
received one
received two

Note that the total execution time is only ~2 seconds since both the 1 and 2 second timeouts execute concurrently.

This example demonstrates how to use Clojure’s core.async library to handle multiple asynchronous operations concurrently, similar to Go’s select statement.