【问题标题】:close! a subscription channel without unsub关闭!没有取消订阅的订阅频道
【发布时间】:2016-01-17 20:14:03
【问题描述】:

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

【问题讨论】:

    标签: clojure clojurescript core.async


    【解决方案1】:

    pub和sub是按照mult实现的:

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

    • 每个 sub 调用都会导致在与相关主题相对应的 mult 上对 tap 进行底层调用。

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

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

    【讨论】:

      【解决方案2】:

      我无法从文档中确定答案,所以我做了一个小的异步实验来确定没有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! 调用不会干扰任何其他订阅的频道,并且每个频道在关闭之前都会看到我们预期的所有结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-07
        • 2020-02-14
        • 1970-01-01
        • 2016-07-06
        • 1970-01-01
        • 2019-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多