关!没有取消订阅的订阅频道

close! a subscription channel without unsub

在没有先使用 unsub 的情况下在订阅频道上使用 close! 有什么影响? 这会产生隐含的 unsub + a close! 的效果还是会产生任何不需要的副作用?

我无法从文档中确定答案,所以我做了一个小的异步实验来确定没有 unsubclose! 是否安全。

(ns pubsub.experiment
  (:require [clojure.core.async :as >]))

(def publisher (>/chan))

(def p (>/pub publisher (constantly nil)))

(def answers (>/chan))

(defn consume
  [label count]
  (let [s (>/sub p nil (>/chan))]
    (>/go-loop [i 0]
      (if (> i count)
        (>/close! s)
        (do
          (>/>! answers [label (>/<! s)])
          (recur (inc i)))))))

(defn -main
  [& args]
  (println "running pubsub experiment")
  (consume :a 1)
  (consume :b 2)
  (consume :c 3)
  (consume :d 4)
  (consume :e 5)
  (>/go-loop []
    (println "result: " (>/<! answers))
    (recur))
  (>/<!! (>/onto-chan publisher (range 10)))
  (System/exit 0))

然后 运行 它(bench.jar 是一个包含 clojure 加上 core.async 和其他几个库的 uberjar)。

$ java -cp ~/bin/bench.jar:. clojure.main -m pubsub.experiment
running pubsub experiment
result:  [:a 0]
result:  [:b 0]
result:  [:c 0]
result:  [:d 0]
result:  [:e 0]
result:  [:a 1]
result:  [:b 1]
result:  [:c 1]
result:  [:d 1]
result:  [:e 1]
result:  [:b 2]
result:  [:c 2]
result:  [:d 2]
result:  [:e 2]
result:  [:c 3]
result:  [:d 3]
result:  [:e 3]
result:  [:d 4]
result:  [:e 4]
result:  [:e 5]
$ 

正如我们所见,close! 调用不会干扰任何其他订阅的频道,并且每个频道在关闭前都会看到我们预期的所有结果。

pubsub 是根据 mult:

实现的
  • 发布频道的每个主题对应于注册该主题的第一个订阅时创建的 mult,

  • 每个 sub 调用都会在与相关主题对应的 mult 上对 tap 进行 under-the-hood 调用。

Mults 在内部设置为移除最终进入关闭通道的 tap(这在 mult 的文档字符串中有记录)。在订阅的上下文中,这意味着如果订阅频道关闭,则在该主题的消息第一次发布到发布频道时,它的点击将从它的 mult 中删除,或者换句话说,close!导致隐式 unsub.

请注意,unsubclose! 都不会导致主题本身(以及相应的 mult)从出版物的注册中删除。如果您希望发生这种情况,可以使用 unsub-all.