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!"))))))))
Core.async is Clojure’s main library for asynchronous programming and communication. It makes asynchronous programming a lot easier by doing much of the heavy lifting for you.The library has a few objectives which you can read about here, but chiefly it aims to:
In particular, it is always safe and efficient to put a Clojure data structure on a channel, without fear of its subsequent use by either the producer or consumer. core.async has obvious similarities to Go channels.
Clojure moves Process A off the thread and moves Process B onto the thread. If Process B starts waiting and Process A’s put or take has finished, then Clojure will move Process B off the thread and put Process A back on it.
It is often desirable to be able to wait for any one (and only one) of a set of channel operations to complete. This powerful facility is made available through the alts! function (for use in go blocks), and the analogous alts!! (alts blocking). If more than one operation is available to complete, one can be chosen at random or by priority.
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):
go-loop
in preference to (go (while true ...))
or (go (loop ...))
alt!
in preference to (let [[result channel]] (alts! ...))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With