This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-02
Channels
- # announcements (6)
- # babashka (21)
- # beginners (38)
- # biff (2)
- # calva (14)
- # cider (5)
- # clerk (4)
- # cljdoc (2)
- # clojure (11)
- # clojure-europe (2)
- # clojure-norway (5)
- # clojure-spec (4)
- # core-typed (8)
- # data-science (5)
- # deps-new (15)
- # events (1)
- # fulcro (2)
- # graalvm (33)
- # holy-lambda (3)
- # hyperfiddle (19)
- # kaocha (1)
- # portal (5)
- # test-check (1)
- # xtdb (9)
- # yamlscript (2)
I'm a little confused on how to properly use mult
in core.async
. The problem I'm trying to solve is to have a chan where I load up events and over time there will be one or more "readers" that connect and process those events. The readers may come and go based on user interactions. I can easily construct a chan that accepts initial events and mult that pushes items to subsequent chans. The thing I can't grasp is how to properly "discard" events from original chan. It seems that if I don't read from original chan and only read from tapped ones, the original keeps all the values it ever received and a new tap gets a copy of all of them. I'd like the tapped channels to only receive items that happen after they tapped-in. Is there a proper way to do this? Is mult not the right tool for the problem?
Add a channel to the tap when a consumer wants messages, close the channel when that consumer is done
I'm running this code in ClojureScript:
(let [ch (async/chan)
mult-ch (async/mult ch)
ch1 (async/chan )
ch2 (async/chan )
put-ch (fn [chan val]
(async/put! chan val
#(js/console.log (str "Put value" val))))
take-confirm (fn [ch-name] #(js/console.log (str "Take " ch-name " ") %))]
(go-loop []
(let [val (async/<! ch1)]
(js/console.log "Take chan 1" val)
(recur)
))
(put-ch ch 1)
(async/tap mult-ch ch1)
(js/console.log "Between puts")
;;(async/take! ch1 (take-confirm "ch1"))
(put-ch ch 2)
(async/tap mult-ch ch2)
;;(async/take! ch1 (take-confirm "ch1"))
(async/take! ch2 (take-confirm "ch2"))
(async/take! ch2 (take-confirm "ch2"))
(js/console.log "after all takes")
)
Output:
Between puts
after all takes
Take chan 1 1
Put value1
Take ch2 1
Put value2
Take chan 1 2
Take ch2 2
As you can see chan2 is tapped after ch1 consumed 1 already, so I assume that value should be gone, but chan2 reads it once it's connected.Taking from chan1 with take! instead of go-loop doesn't change the picture. Chan2 still gets both values.
So there is not really a strict happens before relationship between all those channel operations
The async copy from the input to the output can't run until in js main thread is idle, and that doesn't happen until you have done both taps
Aha, yes you're right. When I ran commands one by one it works as expected. I was confused by pending takes/put when I shoved everything into one let. Thank you!