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
樣式的參數,但是我會留下這個讓你按照你認爲合適的方式去做,因爲它與這個問題是正交的。