Fork me on GitHub
#core-async
<
2017-02-21
>
hlolli12:02:41

does someone know why specifying channel with 1 slot makes a difference to why a return value from channel is printed or not?

user> (require '[clojure.core.async :as async])
WARNING: boolean? already refers to: #'clojure.core/boolean? in namespace: clojure.tools.analyzer.utils, being replaced by: #'clojure.tools.analyzer.utils/boolean?
WARNING: boolean? already refers to: #'clojure.core/boolean? in namespace: clojure.tools.analyzer, being replaced by: #'clojure.tools.analyzer.utils/boolean?
WARNING: bounded-count already refers to: #'clojure.core/bounded-count in namespace: clojure.core.async, being replaced by: #'clojure.core.async/bounded-count
nil
user> (async/go (let [c (async/chan)] (async/>! c 666) (println (async/<! c ))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x3136af71 "clojure.core.async.impl.channels.ManyToManyChannel@3136af71"]
user> (async/go (let [c (async/chan)] (async/>! c 666) (prn (async/<! c ))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x7636fd32 "clojure.core.async.impl.channels.ManyToManyChannel@7636fd32"]
user> (async/go (let [c (async/chan 1)] (async/>! c 666) (prn (async/<! c ))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x7dcccbb6 "clojure.core.async.impl.channels.ManyToManyChannel@7dcccbb6"]
user> 666
user> (async/go (let [c (async/chan 1)] (async/>! c 666) (prn (async/<! c ))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x5a8f3fa1 "clojure.core.async.impl.channels.ManyToManyChannel@5a8f3fa1"]
user> 666
user> 

joshjones13:02:47

@hlolli If the channel is unbuffered … (chan) … then a >! or >!! will park or block, because there are no takers. You need a buffer, a place to put the value, in order to not block/park. So, your print statements are never being executed until you buffer the channel and the >! succeeds

hlolli13:02:59

@joshjones doesn't a (chan) default to 1 buffer slot? Confused.

joshjones13:02:07

When you say “the return value from a channel”, since you are using go blocks, understand that the result of a go block is an implicit channel that contains the result of the body of the go block. This is why every value is a channel, in your example, regardless of whether something prints or not.

joshjones13:02:18

No, (chan) is unbuffered.

hlolli13:02:28

ah ok ok, so >! is a blocking put, and it's actually not not printing but waiting forever for something to take the value. Ok makes sense.

joshjones13:02:42

using a future so it won’t hang your repl:

(future
  (let [c (chan)]
    (println "about to put...")
    (async/>!! c 42)
    (println "won't print...")))
  

joshjones13:02:59

(let [c (chan)]
  (println "about to put...")
  (thread
    (async/>!! c 42))
  (println "just performed a put...")
  (<!! c))
  

hlolli13:02:40

but then I wonder why a buffer of 1 doesn't block, ok then it's a buffer, a nature a buffer. Yes, all clear to me now. I often print from channels, but then it's always from one go macro to another. So it succeeds without buffer.

joshjones13:02:55

>! is a “parking put” … it blocks if there are no takers and the buffer is 0 or full. The difference is that the thread context will be saved, and the thread can be used to execute other code in the meantime. >!! is a true “blocking put” and the thread will not be reused.