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 activity
In 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.