What is the idiomatic way of waiting for a Clojure async channel?
Asked Answered
N

1

5

This is the current version of the code that does very simple job. It starts up 10 go routines and each routine adds 10 messages to the channel. The other end is a while true loop that reads the channel and times out every 500 ms.

I was thinking about having something better. I think the while true loop could be replaced with a recur where the it reads the channel and after each successful read it goes back to read it again. If a timeout happens it just terminates the execution.

I have two questions: - is this the right approach? - how to implement it using idiomatic Clojure

(defn -main [& args]
  (let [c (async/chan)]
    (doseq [i (range 10)]
      (async/go
        (doseq [j (range 10)]
          (Thread/sleep (rand-int 1000))
          (async/>! c (str i " :: " j)))))
    (while  true
    (async/<!!
      (async/go
        (let [[result source] (async/alts! [c (async/timeout 500)])]
          (if (= source c)
            (println "Got a value!" result)
            (println "Timeout!"))))))))
Nevins answered 13/11, 2014 at 19:2 Comment(2)
I'd call any use of Thread/sleep in core.async code always a code smell -- you're filling up your thread pool for no good reason. Can't think of any scenario where <! or <!! from a timeout wouldn't be more appropriate.Forwhy
...and, yes, I'd agree that a loop/recur reading from the channel would be idiomatic.Forwhy
D
7

This is a very common approach, so to answer your first question I'd say yes. There are a few conveniences offered by core.async that could make it a bit more idomatic (though it's really fine the way it is):

  • use go-loop in preference to (go (while true ...)) or (go (loop ...))
  • use alt! in preference to (let [[result channel]] (alts! ...))
Dacoit answered 13/11, 2014 at 21:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.