This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-08-17
Channels
- # admin-announcements (63)
- # beginners (1)
- # boot (83)
- # cider (17)
- # clojure (33)
- # clojure-android (3)
- # clojure-france (3)
- # clojure-gamedev (1)
- # clojure-russia (20)
- # clojure-sg (9)
- # clojurescript (81)
- # core-async (77)
- # cursive (13)
- # datomic (30)
- # hoplon (7)
- # instaparse (54)
- # ldnclj (1)
- # off-topic (4)
- # om (2)
- # onyx (23)
- # re-frame (16)
- # reagent (3)
- # yada (2)
Does anyone have a nifty way to drain the contents of a channel into collection in clojurescript? In clojure I just close the channel then loop blocking takes (that don't block because the channel is closed).
poll!
works. it's not been released yet but is on master (https://github.com/clojure/core.async/commit/d8047c0)
what I want to do is to drain a channel into a collection - specifically so I can store its value and recreate the channel later
I'm using this at the moment:
(defn drain!
"Closes and drains a channel. Synchronously returns a collection of drained messages."
[chan]
(async/close! chan)
(loop [items []]
(if-let [item (#?(:clj async/<!! :cljs poll!) chan)]
(recur (conj items item))
items)))
I know I've dealt with that exact issue of just getting the darn collection out of the result of core.async.into
and it is amazingly frustrating that I cannot remember how. Of course, I'm working in cljs where you can't just do <!!
which makes me think of doing a take! and sending it to identity
but that makes me think that I had a more elegant solution at some time
if you look at that section of code you'll see some of the ways I dealt with these issues
for example, I did this because take needs a func: (take! (step-chan (get-in @state [:gol :cells])) swap-gol!))
inside that go block I wanted to return the result of draining a channel, so I end the go block with this:
(let [new-cells (<! (async/into {} generation-ch))]
(console/time-end "generation-ch")
new-cells)))))
if you do something like my (let [new-cells (<! (async/into {} generation-ch))]
you should be good because you are closing the channel
I don't think it's just me. I think there is a missing piece here in the core.async api. We need something like <!! in cljs.
Once you go async in any way the only way to merge back from callback styles things is to end the asynchronicity
semantically though it feels like something is missing - if you use <! inside a go block you get back another channel that you then need to take from, which puts you right back in the same boat of having to use take! which requires a function but all we want to do is read the final value from the channel.
There is no other way other than callbacks (which might be sugared by go
etc) but there is no way around them as long as you have async code
No way around callbacks, if you're in a single threaded environment. This is why node.js is one giant callback hell and the community has been coming up with hundreds of libaries to somehow avoid those
Unless you do fibers (which rewrite stuff in a state machine). But then: That's exactly what our beloved go
does
but like in the example given by @jthomson where you want a function that takes a channel and returns a collection, without using poll!
Correct, then the only way is poll unless you want to tap into implementation details (AFAIK)
No you just give it the function that deals with the data (take! chch (fn [data] (handle-data data))
atoms are possible, however to illustrate the timing issue:
(-> #(let [!state (atom nil)
chan (async/chan)]
;; Put a value
(go (async/>! chan %))
;; Asynchronously take and swap!
(async/take! chan (partial reset! !state))
;; Deref after some arbitrarily short time
(async/<!! (go @!state)))
(map (range 100))
(doall))
returns
(nil nil nil 3 nil 5 nil 7 8 9 nil 11 12 13 nil 15 nil nil nil 19 nil 21 22 23 24 25 26 nil 28 nil 30 nil nil 33 34 35 36 nil nil 39 nil 41 42 nil nil 45 nil 47 48 49 nil 51 52 nil 54 55 56 57 nil 59 nil nil 62 63 nil 65 nil 67 68 69 70 nil 72 73 nil 75 76 nil 78 79 80 nil 82 83 84 85 nil nil nil 89 90 nil 92 nil nil nil nil nil 98 99)
here's another way: http://tgk.github.io/2013/10/inspect-core-async-channels.html
Yeah, I guess poll! really is the thing that I conceptually want and I haven't used it so I keep trying to come up with solutions without it, which is dumb because the solution that works the way I want is poll!
There is nothing wrong with doing (and staying there) operations asyncronously. The macros we have in cljs thankfully make this pretty nice IMO
For instance I always use a (dochan [x my-ch] (do-whatever x))
in my async code. Where the dochan is again a go
plus some sugar
I intentionally didn't optimize the gol algorithm too much because I wanted something that would tax the cpu so I could figure out how to break it up into chunks and yield to the browser often enough to maintain 60fps even though as the gol proceeds it might take longer than one frame to calculate the next generation.