Print execution time of function in seconds? - clojure

(time(get_report))
Gives me "Elapsed time 32038 ms". But I want seconds, not ms. How can I accomplish this in Clojure?
I want it to print like "Report took 32 seconds".
Update on how I have it now:
(defmacro time
"Evaluates expr and prints the time it took. Returns the value of
expr."
{:added "1.0"}
[expr]
`(let [start# (. System (nanoTime))
ret# ~expr]
(prn (str "Report print time: " (/ (double (- (. System (nanoTime)) start#)) 1000000000.0) " secs"))))
(time(get_report))
This is my gather_report function:
(defn gather_report []
(def list_of_isbns (split_isbns "src/clj_amazon/isbn_list.txt"))
(get_title_and_rank_for_all_isbns list_of_isbns)
)

This is the standard definition:
(defmacro time
"Evaluates expr and prints the time it took. Returns the value of
expr."
{:added "1.0"}
[expr]
`(let [start# (. System (nanoTime))
ret# ~expr]
(prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
ret#))
Note the division form? Just divide by 1000 to convert to seconds. You can change the message aswell:
(defmacro time
"Evaluates expr and prints the time it took. Returns the value of
expr."
{:added "1.0"}
[expr]
`(let [start# (. System (nanoTime))
ret# ~expr]
(prn (str "Report print time: " (/ (double (- (. System (nanoTime)) start#)) 1000000000.0) " secs"))
ret#))
The best way to find the source of something is to look up the Clojure docs for the function, and follow the" source" link.
And this is why you don't use def inside a function definition:
(defn test-fn []
(def some-val 20)
(* some-val some-val)
(test-fn)
(println some-val)
; prints 20!
def creates a global value. You certainly don't want that! Use let instead to limit the scope:
(defn test-fn []
(let [some-val 20]
(* some-val some-val))

You can make a modified version of time macro tailored to your needs:
(defmacro sectime
[expr]
`(let [start# (. System (currentTimeMillis))
ret# ~expr]
(prn (str "Elapsed time: " (/ (double (- (. System (currentTimeMillis)) start#)) 1000.0) " secs"))
ret#))

Related

Memoize doesn't work for fibonacci example

(time (fib 30))
;; "Elapsed time: 8179.04028 msecs"
;; Fibonacci number with recursion and memoize.
(def m-fib
(memoize (fn [n]
(condp = n
0 1
1 1
(+ (m-fib (dec n)) (m-fib (- n 2)))))))
(time (m-fib 30))
;; "Elapsed time: 1.282557 msecs"
This the example code from https://clojuredocs.org/clojure.core/memoize, but when I run it on my browser, the time doesn't change at all. I am wondering why it is?
I don't know what browser-based REPL you're using, but the left-hand column shows the result of the function call, not the time, which is why both values are the same. Both functions compute the same Fibonacci number.
The time macro is designed to wrap arbitrary expressions without having to change the structure of the code, so it returns the same value that's returned by the wrapped expression and prints the execution time to standard out. Essentially, the expression (time (m-fib 30)) is expanded to
(let [start (. System (nanoTime))
ret (m-fib 30)]
(println (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start)) 1000000.0) " msecs"))
ret)
So to see the execution time in your REPL, you'll need to see the printed output of an expression.

Memoize over one parameter

I have a function which takes two inputs which I would like to memoize. The output of the function only depends on the value of the first input, the value of the second input has no functional effect on the outcome (but it may affect how long it takes to finish). Since I don't want the second parameter to affect the memoization I cannot use memoize. Is there an idiomatic way to do this or will I just have to implement the memoization myself?
I'd recommend using a cache (like clojure.core.cache) for this instead of function memoization:
(defonce result-cache
(atom (cache/fifo-cache-factory {})))
(defn expensive-fun [n s]
(println "Sleeping" s)
(Thread/sleep s)
(* n n))
(defn cached-fun [n s]
(cache/lookup
(swap! result-cache
#(cache/through
(fn [k] (expensive-fun k s))
%
n))
n))
(cached-fun 111 500)
Sleeping 500
=> 12321
(cached-fun 111 600) ;; returns immediately regardless of 2nd arg
=> 12321
(cached-fun 123 600)
Sleeping 600
=> 15129
memoize doesn't support caching only on some args, but's pretty easy to make it yourself:
(defn search* [a b]
(* a b))
(def search
(let [mem (atom {})]
(fn [a b]
(or (when-let [cached (get #mem a)]
(println "retrieved from cache")
cached)
(let [ret (search* a b)]
(println "storing in cache")
(swap! mem assoc a ret)
ret)))))
You can wrap you function into another function (with one parameter) and call it the function with second default parameter. Then you can memoize the new function.
(defn foo
[param1]
(baz param1 default-value))

Start and Stop core.async Interval

consider the following core-async code. It prints the string "tick" every 2 seconds:
(go-loop []
(<! (timeout 2000))
(prn "tick")
(recur))
I'm looking for a possibility to start and stop the interval from outside via functions.
The only thing that came to my mind was this:
(def running (atom false))
(defn start []
(reset! running true)
(go (loop []
(<! (timeout 2000))
(prn "tick")
(when #running (recur)))))
(defn stop []
(reset! running false))
Is this the way to go? Or would you do something else?
Here's what I would do:
(require '[clojure.core.async :as a])
(defn interval [f msecs]
(let [timing (a/chan)
kickoff
#(a/go
(a/<! (a/timeout msecs))
(a/>! timing true))]
(a/go-loop []
(when (a/<! timing)
(a/go (f))
(kickoff)
(recur)))
(kickoff)
#(a/close! timing)))
Example:
(let [i (interval #(prn "tick") 2000)]
(Thread/sleep 7000)
(i))
;; "tick"
;; "tick"
;; "tick"
;;=> nil
This way, all your state is local and is handled via channels and go blocks, rather than using a global atom. Since the work done in each iteration of the loop is more or less constant, your actual interval time should be fairly close to the number of msecs you pass in.
Or if you want to guarantee that the different calls to f are executed in chronological order, you could do something like this instead:
(require '[clojure.core.async :as a])
(defn interval [f msecs]
(let [action (a/chan (a/dropping-buffer 1))
timing (a/chan)
kickoff
#(a/go
(a/<! (a/timeout msecs))
(a/>! timing true))]
(a/go-loop []
(when (a/<! action)
(f)
(recur)))
(a/go-loop []
(if (a/<! timing)
(do
(a/>! action true)
(kickoff)
(recur))
(a/close! action)))
(kickoff)
#(a/close! timing)))
(The usage of this function is the same as that of my earlier interval function.)
Here all the calls to f are in the same loop. I'm using a dropping buffer, so if a call to f takes longer than msecs, future calls may start getting dropped to keep up.
Here is another way, you could go
(defn start []
(let [ctl (chan 0 )]
(go-loop []
(alt!
(timeout 2000) (do
(prn "tick")
(recur))
ctl (prn "Exit ")))
ctl))
(let [w (start) ]
(Thread/sleep 7000)
(>!! w "stop"))
;;=> "tick"
"tick"
"Exit"
You don't need to define state in namespace. Start function is returning chan to do stop in future.

Sleeping barber in Clojure

I'm implementing Sleeping barber using core.async. My current code is:
(def workingtime 10000)
(defn barber [in waiting-room]
(go-loop [served-customers 0]
(let [[v] (alts! [waiting-room in])]
(if (= v :close)
served-customers
(do (Thread/sleep 20)
(recur (inc served-customers)))))))
(defn customers [in waiting-room]
(go-loop [customers-overall 0]
(let [customer-arrival-interval (timeout (+ 10 (rand-int 20)))
[v] (alts! [in customer-arrival-interval])]
(if (= v :close)
customers-overall
(do (>! waiting-room :customer)
(recur (inc customers-overall)))))))
(defn -main [& args]
(let [in (chan)
waiting-room (chan (dropping-buffer 3))
barber-ch (barber in waiting-room)
customers-ch (customers in waiting-room)]
(println "opening the shop for 10 seconds...")
(Thread/sleep workingtime)
(>!! in :close)
(>!! in :close)
(println "closing the shop...")
(println (str "Served " (<!! barber-ch) " customers"))
(println (str "Overall " (<!! customers-ch) " customers came"))))
Is it a correct solution? Can it be improved to make it more Clojure-like?
I wanted to use alt! instead of alts! which makes code easier to read:
(defn barber [in]
(go-loop [served-customers 0]
(alt!
waiting-room (do (Thread/sleep 20)
(recur (inc served-customers)))
in served-customers)))
Runtime throws an exception: Can only recur from tail position. Can I still use alt!?
You could solve the alt!/recur problem by rewriting to:
(defn barber [in]
(go-loop [served-customers 0]
(if (= :waiting-room
(a/alt!
waiting-room ([result] :waiting-room) ;; you could also use result if needed
in ([result] :in))) ;; same here
(do (Thread/sleep 20)
(recur (inc served-customers)))
served-customers)))

Dead simple Fork-Join concurrency in Clojure

I have two costly functions that are independent. I want to run them in parallel. I don't want to deal with futures and such (I'm new to Clojure and easily confused).
I'm looking for a simple way to run two functions concurrently. I want it to work like the following
(defn fn1 [input] ...) ; costly
(defn fn2 [input] ...) ; costly
(let [[out1 out2] (conc (fn1 x) (fn2 y))] ...)
I want this to return a vector with a pair of outputs. It should only return once both threads have terminated. Ideally conc should work for any number of inputs. I suspect this is a simple pattern.
Using futures is very easy in Clojure. At any rate, here is an answer that avoids them
(defn conc [& fns]
(doall (pmap (fn [f] (f)) fns)))
pmap uses futures under the hood. doall will force the sequence to evaluate.
(let [[out1 out2] (conc fn1 fn2)]
[out1 out2])
Note, that I destructured out1 and out2 in an attempt to preserve your example.
You do need a macro to preserve the desired syntax, though there are other ways of obtaining the same behavior, as the other answers indicate. Here is one way to do it:
(defn f1 [x] (Thread/sleep 500) 5)
(defn f2 [y] 2)
(defmacro conc [& exprs]
`(map deref
[~#(for [x# exprs] `(future ~x#))]))
(time (let [[a b] (conc (f1 6) (f2 7))]
[a b]))
; "Elapsed time: 500.951 msecs"
;= (5 2)
The expansion shows how it works:
(macroexpand-1 '(conc (f1 6) (f2 7)))
;= (clojure.core/map clojure.core/deref [(clojure.core/future (f1 6))
;= (clojure.core/future (f2 7))])
You specified two functions but this should work with any number of expressions.
I understand you don't want your final solution to expose futures though it is useful to illustrate how to do this with futures, and then wrap them in something that hides this detail:
core> (defn fn1 [input] (java.lang.Thread/sleep 2000) (inc input))
#'core/fn1
core> (defn fn2 [input] (java.lang.Thread/sleep 3000) (* 2 input))
#'core/fn2
core> (time (let [f1 (future (fn1 4)) f2 (future (fn2 4))] #f1 #f2))
"Elapsed time: 3000.791021 msecs"
then we can wrap that up in any of the many clojure wrappers around futures. the simplest being just a function which takes two functions and runs them in parallel.
core> (defn conc [fn1 fn2]
(let [f1 (future (fn1))
f2 (future (fn2))] [#f1 #f2]))
#'core/conc
core> (time (conc #(fn1 4) #(fn2 4)))
"Elapsed time: 3001.197634 msecs"
This avoids the need to write it as a macro by having conc take the function to run instead of the body to evaluate, and then create the functions to pass to it by putting # infront of the calls.
This can also be written with map and future-call:
core> (map deref (map future-call [#(fn1 4) #(fn2 42)]))
(5 84)
You can then improce conc until it resembles (as Julien Chastang wisely points out) pmap