Am I correct in that the usage of Thread/sleep
is not recommended as in example from Brave clojure? https://www.braveclojure.com/core-async/#alts__
(defn upload
[headshot c]
(go (Thread/sleep (rand 100))
(>! c headshot)))
Should one use thread
instead (with >!!
since >!
cannot be used outside of go
)?And btw. why does this keep printing different channel "strings" (I expected the same channels/pictures would lead to the same .toString representation):
(let [c1 (a/chan)
c2 (a/chan)
c3 (a/chan)]
(upload "serious.jpg" c1)
(upload "fun.jpg" c2)
(upload "sassy.jpg" c3)
(let [[headshot channel] (a/alts!! [c1 c2 c3])]
(printf "Sending headshot notification for %s (%s)\n" headshot channel)))
Sending headshot notification for fun.jpg (clojure.core.async.impl.channels.ManyToManyChannel@77b6771a)
Sending headshot notification for fun.jpg (clojure.core.async.impl.channels.ManyToManyChannel@6c1ec55e)
Sending headshot notification for fun.jpg (clojure.core.async.impl.channels.ManyToManyChannel@7587449a)
Sending headshot notification for fun.jpg (clojure.core.async.impl.channels.ManyToManyChannel@5e13ba2d)
Sending headshot notification for serious.jpg (clojure.core.async.impl.channels.ManyToManyChannel@20ada533)
Sending headshot notification for serious.jpg (clojure.core.async.impl.channels.ManyToManyChannel@3e025718)
thread sleep will block worker thread that execute go-block code
Calling append-to-file
inside the go
block (https://www.braveclojure.com/core-async/#Queues) also doesn't look like the best approach
another question: how do people monitor core.async channels in practice? I couldn't find much about this stuff, only this http://tgk.github.io/2013/10/inspect-core-async-channels.html
The more appropriate thing to do in that snippet would be (a/timeout (rand 100))
rather than the sleep
Yes, thanks, also found that option. In general, it seems that blocking calls are tricky. Either you have some sort of non-blocking IO lib or use threads with limited thread pool?
yep. The only "blocking" calls that should be in go blocks are the parking >! <! operations.
besides that you can quickly get around things by tossing the call into a a/thread
call.
and also remember that channels are very useful even outside of a core.async, go block context
@markmarkmark you mean using the blocking variants like >!!
, <!!
, alts!!
, etc., perhaps with buffered channels? kind of like queues for decoupling components of your system?
right. you can just use those with plain threads.
The channels don't even need to have buffers, but if you give them buffers then they are perfectly fine queues.
There are plenty of reasons to have them without buffers still. See SynchronousQueue
in Java
for instance, you could have a plain thread that is blocking on io and then >!!
into a channel. one or more go blocks could be parked on that channel waiting for the input.
a potential way to push the I/O to the outer edges of the program and ferry it into the core.async machinery if needed.
we don't really monitor channels at work. we have some custom buffer types that report metrics, but those aren't really used, we mostly generate metrics for processes reading and writing to channels. how often they loop, how long each loop takes, how many messages they are sending out as they loop
using custom buffer types for monitoring channels isn't that great, because buffers are only used if a channel cannot immediately hand off
a lot of the system where we use core.async the heaviest is very actor like, loops around reading from an input channel, and handling the message