Non Blocking Channel Operations in Clojure
Basic sends and receives on channels are blocking in Clojure as well. However, we can use alt! with a :default clause to implement non-blocking operations, similar to Go’s select with default.
(ns non-blocking-channel-operations
(:require [clojure.core.async :as async :refer [chan go >! <! alt!]]))
(defn main []
(let [messages (chan)
signals (chan)]
; Here's a non-blocking receive. If a value is
; available on `messages` then `alt!` will take
; the `messages` case with that value. If not
; it will immediately take the `:default` case.
(alt!
messages ([msg] (println "received message" msg))
:default (println "no message received"))
; A non-blocking send works similarly. Here `msg`
; cannot be sent to the `messages` channel, because
; the channel has no buffer and there is no receiver.
; Therefore the `:default` case is selected.
(let [msg "hi"]
(alt!
[[messages msg]] (println "sent message" msg)
:default (println "no message sent")))
; We can use multiple cases above the `:default`
; clause to implement a multi-way non-blocking
; select. Here we attempt non-blocking receives
; on both `messages` and `signals`.
(alt!
messages ([msg] (println "received message" msg))
signals ([sig] (println "received signal" sig))
:default (println "no activity"))))
(main)To run this program:
$ lein run
no message received
no message sent
no activityIn Clojure, we use the core.async library to work with channels and asynchronous operations. The alt! macro is used for non-blocking operations, similar to Go’s select. The :default case in alt! serves the same purpose as the default case in Go’s select.
The structure of the program remains similar, with non-blocking receives and sends demonstrated using alt!. The multi-way non-blocking select is also implemented using alt! with multiple cases.
Note that in Clojure, we use vectors [] to represent channel operations within alt!. For sending, we use a nested vector [[channel value]], and for receiving, we use a vector with a binding form [variable-name].
This example demonstrates how Clojure’s core.async library provides similar capabilities to Go’s channel operations, allowing for non-blocking communication between concurrent processes.