I want to pass a form to be evaluated to a target thread pool as a future via the claypoole library in clojure.
I tried to pass off the body of a function to a thread pool, and I was expecting that body to be evaluated on a thread rather than inline.
The code I have looks like this:
(defn in-thread [thread & body] (claypoole/future thread body))
Which gets called like:
(defonce pool (claypoole/threadpool 20))
(defn do-something [pool]
(in-thread pool
(Thread/sleep 5000)
(println "foo")))
After some testing, I've come to the conclusion that that body
is being evaluated when I call in-thread
, making my whole solution not actually do anything meaningful. I know there's some sort of basic concept I'm missing, but every time I try to look into macros my head starts to spin.
How would I make the in-thread
function into a macro that passes off the body into the thread pool to execute, rather than the result?
When you use a function - that is, a construct created with defn
/fn
- all its arguments will be evaluated before the function itself is called. So in your case, the in-thread
function gets called with the results of (Thread/sleep ...)
and (println ...)
, and both are nil
.
In order to pass forms around without actually evaluating them, you either have to quote those forms and use eval
later or use a macro, which is a much more common approach.
In your case, it would be enough to replace the definition of in-thread
with:
(defmacro in-thread [thread & body]
`(claypoole/future ~thread ~@body))
However, notice that it becomes just a wrapper around claypoole/future
that doesn't do anything by itself. And claypoole/future
itself is already a macro - you don't even need in-thread
! All you need is already implemented by claypoole/future
, so you can just use this:
(defonce pool (claypoole/threadpool 20))
(defn do-something [pool]
(claypoole/future pool
(Thread/sleep 5000)
(println "foo")))