1
您好我正在寻找一种方法来计算clojure中的函数调用,以便例如我可以找出哪些函数被调用最频繁。理想情况下,我希望这对用户是透明的,这样如果他们添加一个他们不知道或关心这个过程的函数。任何帮助将不胜感激。在clojure计数函数调用
请多关照 迈克尔
您好我正在寻找一种方法来计算clojure中的函数调用,以便例如我可以找出哪些函数被调用最频繁。理想情况下,我希望这对用户是透明的,这样如果他们添加一个他们不知道或关心这个过程的函数。任何帮助将不胜感激。在clojure计数函数调用
请多关照 迈克尔
可以使用with-meta
存储呼叫计数的atom
并附加一个访问该功能:
(def sqrt
(let [n (atom 0)]
(with-meta
(fn [x]
(swap! n inc)
(Math/sqrt x))
{::call-count (fn [] @n)})))
例子:
((::call-count (meta sqrt))) ;=> 0
(sqrt 0) ;=> 0.0
(sqrt 1) ;=> 1.0
(sqrt 2) ;=> 1.4142135623730951
((::call-count (meta sqrt))) ;=> 3
(sqrt 3) ;=> 1.7320508075688772
(sqrt 4) ;=> 2.0
(sqrt 5) ;=> 2.23606797749979
((::call-count (meta sqrt))) ;=> 6
这在某些情况下可能会导致相当大的放缓,但计数将始终正确更新,因为Clojure原子s是线程安全的。另一种方法是使用add-watch
而不是deref
,但哪一个更好取决于你的情况。如果你愿意,你甚至可以同时使用它们。
你可以抽象掉了defcounted
宏来定义呼叫计数功能的细节和call-count
功能取回调用计数函数的调用次数:
(defmacro defcounted [sym params & body]
`(def ~sym
(let [n# (atom 0)]
(with-meta
(fn ~params
(swap! n# inc)
[email protected])
{::call-count (fn [] @n#)}))))
(defn call-count [f]
((::call-count (meta f))))
(defcounted sqrt [x]
(Math/sqrt x))
例子:
(call-count sqrt) ;=> 0
(sqrt 0) ;=> 0.0
(sqrt 1) ;=> 1.0
(sqrt 2) ;=> 1.4142135623730951
(call-count sqrt) ;=> 3
(sqrt 3) ;=> 1.7320508075688772
(sqrt 4) ;=> 2.0
(sqrt 5) ;=> 2.23606797749979
(call-count sqrt) ;=> 6
此外,由于此处您将元数据附加到函数本身而不是var,因此您也可以将此技术扩展为匿名函数。
显然defcounted
缺少很多defn
的功能,所以对用户来说不是很透明。在解决这个问题时,你可以使用clojure.spec
来更容易地解析defn
样式的参数,但是我会留下这个让你按照你认为合适的方式去做,因为它与这个问题是正交的。