【发布时间】:2016-01-17 20:14:03
【问题描述】:
在订阅频道上使用close! 而不先使用unsub 会有什么影响?
这会产生隐含的unsub + close! 的效果,还是会产生任何不需要的副作用?
【问题讨论】:
标签: clojure clojurescript core.async
在订阅频道上使用close! 而不先使用unsub 会有什么影响?
这会产生隐含的unsub + close! 的效果,还是会产生任何不需要的副作用?
【问题讨论】:
标签: clojure clojurescript core.async
pub和sub是按照mult实现的:
发布频道的每个主题对应于在注册该主题的第一个订阅时创建的 mult,
每个 sub 调用都会导致在与相关主题相对应的 mult 上对 tap 进行底层调用。
Mults 在内部设置为删除最终进入封闭通道的水龙头(这在 mult 的文档字符串中记录)。在订阅的上下文中,这意味着如果订阅通道关闭,则在该主题的消息第一次发布到发布通道时,它的 tap 将从其 mult 中移除,或者换句话说,close! 确实会导致隐式unsub。
请注意,unsub 和 close! 都不会导致主题本身(以及相应的 mult)从出版物的注册表中删除。如果您希望这种情况发生,您可以使用unsub-all。
【讨论】:
我无法从文档中确定答案,所以我做了一个小的异步实验来确定没有unsub 的close! 是否安全。
(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! 调用不会干扰任何其他订阅的频道,并且每个频道在关闭之前都会看到我们预期的所有结果。
【讨论】: