在go例程中包含函数调用

时间:2014-04-22 02:22:59

标签: clojure core.async

我试图在函数中包装一个go例程(如下面的方法1)。方法2完全正常,但方法1没有。唯一的区别是在方法1中,我将一个通道作为参数传递给一个函数,并且put在函数内部。关于例程和函数的确切规则是什么?

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

;方法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))))

;方法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"))))

我还注意到,如果我删除方法1中的go并将其移动到do it功能,如下所示,该函数将打印" g"但不是" f"但否则工作正常。为什么呢?

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

1 个答案:

答案 0 :(得分:1)

>!<!并非真正被调用的函数(请参阅herehere)。 go宏标识这两个符号,并根据这两个运算符的语义自动生成代码。所以这个宏无法知道函数在内部使用>!<!运算符,因为它只是调用该函数的表单。

方法1 实际上是在每次调用doit时抛出异常,因为>!<!的实际代码只是一个始终失败的断言。在以lein repl开头的REPLy会话中评估此方法的代码会多次显示异常Exception in thread "async-dispatch-46" java.lang.AssertionError: Assert failed: >! used not in (go ...) block(确切地说是10)。如果您通过nREPL客户端使用REPL,则可能看不到这一点,因为异常是在服务器中异步抛出的,客户端没有考虑到这一点。

此外,您可以使用(print "something\n")而不是使用(println "something"),而不是与您的问题真正相关,但我认为我提到了这一点。