【问题标题】:Threadlocal counter in ClojureClojure 中的线程本地计数器
【发布时间】:2011-11-15 06:30:08
【问题描述】:

我有一个网络应用程序,我希望能够跟踪给定函数在请求(即线程)中被调用的次数。

我知道可以使用 ref 以非线程本地方式进行操作,但我将如何在本地进行线程操作?

【问题讨论】:

    标签: clojure thread-local


    【解决方案1】:

    您可以在参考文献中保留ThreadLocal 的实例。每次您需要增加它时,只需读取值,增加它并返回。在请求开始时,你应该用 0 初始化线程本地,因为线程可能会被不同的请求重用。

    【讨论】:

    • 在 ThreadLocal 中保留一个 ref 肯定比其他方式更容易?我不确定将 ThreadLocal 保留在 ref 中是否有意义,因为 ThreadLocals 是可变的并且不与 refs 协调;无论如何,重试交易都会中断。
    【解决方案2】:

    您可以使用动态全局变量,绑定到带有binding 的值并结合特殊形式set! 来更改其值。与binding 绑定的变量是线程本地的。每次在 with-counter 调用中调用 my-fn 时,以下内容将增加 *counter*

    (def ^{:dynamic true} *counter*)
    
    (defmacro with-counter [& body]
      `(binding [*counter* 0]
         ~@body
         *counter*))
    
    (defn my-fn []
      (set! *counter* (inc *counter*)))
    

    为了演示,请尝试:

    (with-counter (doall (repeatedly 5 my-fn)))
    ;; ==> 5
    

    欲了解更多信息,请参阅http://clojure.org/vars#set

    【讨论】:

    • 这只适用于宏的上下文。如果您的代码不是调用者(例如 ring 或 HTTP 服务器调用您的代码来处理请求),它将无法工作。例如:像这样修改(def(def ^{:dynamic true} *counter* 10) 执行(with-counter,然后检查counter(with-counter (doall (repeatedly 5 my-fn))) . => 5 *counter* => 10
    【解决方案3】:

    useful 中有一个名为 thread-local 的工具。例如,您可以写(def counter (thread-local (atom 0)))。这将创建一个全局变量,当derefed 时,将为每个线程生成一个新原子。所以你可以用@@counter读取当前值,或者用(swap! @counter inc)增加它。当然,您也可以使用@counter 获取原子本身,然后将其视为普通原子。

    【讨论】:

      猜你喜欢
      • 2022-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-17
      相关资源
      最近更新 更多