Question

I am trying to wrap a go routine inside a function (as in Method 1 below). Method 2 works perfectly fine, but Method 1 doesn't. The only difference is that in Method 1, I am passing a channel as a parameter to a function and the put is inside the function. What are the exact rules concerning go routines and functions?

(defn doit [ch i]
  (print "g\n")
  (async/>! ch i)
  (print "f\n"))

;Method 1

(let [c1 (async/chan)]
  (async/go (while true
      (let [[v ch] (async/alts! [c1])]
         (println "Read" v "from" ch))))
  (dotimes [i 10]
     (async/go (doit c1 i))))

;Method 2

(let [ch (async/chan)]
   (async/go (while true       
      (let [[v ch] (async/alts! [ch])]
          (println "Read" v "from" ch))))
   (dotimes [i 10]
     (async/go
       (print "g\n")
       (async/>! ch i)
       (print "f\n"))))

I also noticed that if I remove the go in Method 1 and move it to the do it function as shown below, the function prints "g" but not "f" but otherwise works fine. Why?

(defn doit [ch i]
  (async/go
   (print "g\n")
   (async/>! ch i)
   (print "f\n")))
Was it helpful?

Solution

>! and <! are not really functions that get called (see here and here). The go macro identifies these two symbols and auto-magically generates code according to the semantics of those two operators. So this macro has no way of knowing that a function uses the >! or <! operator internally, since all it gets is the forms that calls that function.

Method 1 is actually throwing an exception on each call to doit since the actual code for >! and <! is just an assertion that always fails. Evaluating the code for this method in a REPLy session started with lein repl shows the exception Exception in thread "async-dispatch-46" java.lang.AssertionError: Assert failed: >! used not in (go ...) block a bunch of times (10 to be exact). If you are using a REPL through an nREPL client you might not be seeing this because the exception is thrown asynchronously in the server and the client is not taking this into account.

Additionally instead of using (print "something\n") you could just use (println "something"), not really related to your question but thought I mentioned this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top