如何在clojure中记录函数调用的时间

如何在clojure中记录函数调用的时间,clojure,clojure-java-interop,Clojure,Clojure Java Interop,我是Clojure的新手。我正在使用java调用Clojure函数,我想记录一行Clojure代码执行所需的时间: 假设我的clojure函数是: (defn sampleFunction [sampleInput] (fun1 (fun2 sampleInput)) 上面的函数是我从java调用的,它返回一些字符串值,我想记录执行fun2所花费的时间 我还有一个函数logTime,它会将传递给它的参数写入某个数据库: (defn logTime [ti

我是Clojure的新手。我正在使用java调用Clojure函数,我想记录一行Clojure代码执行所需的时间:

假设我的clojure函数是:

     (defn sampleFunction [sampleInput]
         (fun1 (fun2 sampleInput))
上面的函数是我从java调用的,它返回一些字符串值,我想记录执行fun2所花费的时间

我还有一个函数logTime,它会将传递给它的参数写入某个数据库:

      (defn logTime [time]
            .....
      )
我的问题是:如何修改sampleFunction(..)以调用logTime来记录执行fun2所花费的时间


提前感谢您。

我不完全确定您的代码的不同部分是如何组合在一起并与Java进行互操作的,但这里有一些东西可以按照您描述的方式工作

要获取一段代码的执行时间,有一个名为
time
的核心函数。但是,此函数不返回执行时间,它只打印它。。。因此,如果要将该时间记录到数据库中,我们需要编写一个宏来捕获
fun2
的返回值以及执行所需的时间:

(defmacro time-execution
  [& body]
  `(let [s# (new java.io.StringWriter)]
     (binding [*out* s#]
       (hash-map :return (time ~@body)
                 :time   (.replaceAll (str s#) "[^0-9\\.]" "")))))
这个宏所做的是将标准输出绑定到Java
StringWriter
,这样我们就可以使用它来存储
time
函数打印的任何内容。为了返回
fun2
的结果及其执行所需的时间,我们将这两个值打包在一个哈希映射中(也可以是其他集合-稍后我们将对其进行分解)。请注意,我们正在计时的代码被包装在对
time
的调用中,因此我们触发打印副作用并在
s#
中捕获它。最后,
.replaceAll
只是为了确保我们只提取实际的数值(以毫秒为单位),因为
time
打印的是
格式的内容“经过的时间:0.014617毫秒”

将其合并到您的代码中,我们需要像这样重写
sampleFunction

(defn sampleFunction [sampleInput]
  (let [{:keys [return time]} (time-execution (fun2 sampleInput))]
    (logTime time)
    (fun1 return)))

我们只是对哈希映射进行分解,以访问
fun2
的返回值和执行所需的时间,然后使用
logTime
记录执行时间,最后,我们在
fun2
的返回值上调用
fun1
,我不能完全确定代码的不同部分是如何组合在一起并与Java进行互操作的,但这里有一些东西可以按照您描述的方式工作

要获取一段代码的执行时间,有一个名为
time
的核心函数。但是,此函数不返回执行时间,它只打印它。。。因此,如果要将该时间记录到数据库中,我们需要编写一个宏来捕获
fun2
的返回值以及执行所需的时间:

(defmacro time-execution
  [& body]
  `(let [s# (new java.io.StringWriter)]
     (binding [*out* s#]
       (hash-map :return (time ~@body)
                 :time   (.replaceAll (str s#) "[^0-9\\.]" "")))))
这个宏所做的是将标准输出绑定到Java
StringWriter
,这样我们就可以使用它来存储
time
函数打印的任何内容。为了返回
fun2
的结果及其执行所需的时间,我们将这两个值打包在一个哈希映射中(也可以是其他集合-稍后我们将对其进行分解)。请注意,我们正在计时的代码被包装在对
time
的调用中,因此我们触发打印副作用并在
s#
中捕获它。最后,
.replaceAll
只是为了确保我们只提取实际的数值(以毫秒为单位),因为
time
打印的是
格式的内容“经过的时间:0.014617毫秒”

将其合并到您的代码中,我们需要像这样重写
sampleFunction

(defn sampleFunction [sampleInput]
  (let [{:keys [return time]} (time-execution (fun2 sampleInput))]
    (logTime time)
    (fun1 return)))
我们只是对哈希映射进行分解,以访问
fun2
的返回值和执行所需的时间,然后使用
logTime
记录执行时间,最后,我们通过调用
fun2
的返回值
fun1
来完成。如果您想捕获一个或多个函数的执行时间并在多次调用中累积,库为您提供了许多选项。例如:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [tupelo.profile :as prof]))

(defn add2 [x y] (+ x y))
(prof/defnp fast [] (reduce add2 0 (range 10000)))
(prof/defnp slow [] (reduce add2 0 (range 10000000)))

(dotest
  (prof/timer-stats-reset)
  (dotimes [i 10000] (fast))
  (dotimes [i 10] (slow))
  (prof/print-profile-stats)
  )
结果:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 14
--------------------------------------

Testing tst.demo.core

    ---------------------------------------------------------------------------------------------------
    Profile Stats:
       Samples       TOTAL        MEAN      SIGMA           ID
        10000        0.955     0.000096   0.000045   :tst.demo.core/fast                                                              
           10        0.905     0.090500   0.000965   :tst.demo.core/slow                                                              
    ---------------------------------------------------------------------------------------------------
如果您想要单个方法的详细时间安排,这是您所需要的。从
快速工作台
函数开始。

如果您想要捕获一个或多个函数的执行时间并在多个调用中累积时间,库为您提供了许多选项。例如:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [tupelo.profile :as prof]))

(defn add2 [x y] (+ x y))
(prof/defnp fast [] (reduce add2 0 (range 10000)))
(prof/defnp slow [] (reduce add2 0 (range 10000000)))

(dotest
  (prof/timer-stats-reset)
  (dotimes [i 10000] (fast))
  (dotimes [i 10] (slow))
  (prof/print-profile-stats)
  )
结果:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 14
--------------------------------------

Testing tst.demo.core

    ---------------------------------------------------------------------------------------------------
    Profile Stats:
       Samples       TOTAL        MEAN      SIGMA           ID
        10000        0.955     0.000096   0.000045   :tst.demo.core/fast                                                              
           10        0.905     0.090500   0.000965   :tst.demo.core/slow                                                              
    ---------------------------------------------------------------------------------------------------

如果您想要单个方法的详细时间安排,这是您所需要的。首先使用
快速工作台功能。

谢谢。它解决了这个问题。有没有一种方法可以在不返回map的情况下执行,比如时间执行可以记录时间,并且应该只返回结果?我试过下面的方法,但似乎不起作用。你能告诉我为什么吗?(defmacro-time-execution[&body]`(let[s#(new java.io.StringWriter)](绑定[out s#](let[return(time~@body)](logTime(.replaceAll(str s#)“[^0-9\\\\.]”)return))(defn-sampleFunction[sampleInput](fun1(logTime-time)))与您编写的宏绑定,您可能想让
sampleFunction
成为
(defn sampleFunction[sampleInput](fun1(时间执行(fun2 sampleInput)))
?您是对的。我也是这个意思。但它给出了异常:由以下原因引起:clojure.lang.ExceptionInfo:对clojure.core/let的调用不符合规范。{:clojure.spec.alpha/problems……。如果有任何帮助来修复此错误,我们将不胜感激。我可以通过将let替换为def:)来实现此功能。它解决了此问题。是否有一种方法可以在不返回map的情况下完成此操作,如time execution可以记录时间,并且应该只返回结果?我正在尝试类似于下面的操作,但它似乎不太有用你能告诉我为什么吗?(defmacro time execution[&body]`(let[s#(new java.io.StringWriter)](binding[out s#](let[return(time~@body)](logTime(.replaceAll(