views:

818

answers:

4

I've read a lot about how great Clojure is when it comes to concurrency, but none of the tutorials I've read actually explain how to create a thread. Do you just do (.start (Thread. func)), or is there another way that I've missed?

+3  A: 

Yes, the way that you start a Java Thread in Clojure is something like what you have there.

However, the real question is: why would you want to do that? Clojure has much better concurrency constructs than threads.

If you look at the canonical concurrency example in Clojure, Rich Hickey's ant colony simulation, you will see that is uses exactly 0 threads. The only reference to java.lang.Thread in the entire source is three calls to Thread.sleep, whose sole purpose is to slow the simulation down so that you can actually see what is going on in the UI.

All the logic is done in Agents: one agent for every ant, one agent for the animation and one agent for the pheromone evaporation. The playing field is a transactional ref. Not a thread nor lock in sight.

Jörg W Mittag
This is not correct. Clojure uses of course threads under the hood. But it provides abstractions to syncronise and coordinate these threads, eg. futures, pmap or agents. And then there are problems, where you want to use threads with the java.util.concurrent machinery.
kotarak
I'd give Jörg the benefit of the doubt that when he says threads he means the Thread API, but that should be made clear.
Mike Douglas
What Clojure uses in its internal runtime to implement agents, futures and whatnot is Rich Hickey's business, not mine. The fact that today the JVM version of Clojure happens to use Thread pools is completely irrelevant to the language semantics. Tomorrow Rich might change his mind and implement them as Continuations, the .NET version of Clojure might implement them as `Task`s, ClojureScript (the JavaScript version of Clojure) might implement them as HTML5 Web Workers, and a hypothetical future Erlang-hosted version might implement them as Actors. As a Clojure user, I'll never know.
Jörg W Mittag
Not true. `pmap` will underperform `map` if the task is small enough. Abstractions are leaky, and you should always understand what is happening underneath.
Mike Douglas
Clojure is often leaky on purpose. It exposes Java so you can take advantage of it. (Clojure strings == Java strings etc.) Clojure isn't going to break compatibility with plain Java Threads any time soon, would be my guess.
Brian Carper
@Mike the pmap abstraction is not leaky ..noone ever stated that pmap will out perform map every single time.
Surya
@Surya Depends on your definition of leaky :) The fact that performing actions in parallel would be slower than actions performed in sequence seems impossible in an idealized (ie. perfectly abstracted) world. Proper application of `pmap` requires that you understand the cost of spawning and coordinating threads, so right there you've escaped the world of "ideal parallel application". That's what I mean by leaky; it wasn't meant as a criticism of the language. As Brian mentioned, it can often be a desirable aspect.
Mike Douglas
+3  A: 

Programming Clojure doesn't address that question until page 167: "Use Agents for Asynchronous Updates".

Before you go starting threads, please note that Clojure will multitask on its own, given half a chance. I've written programs blithely ignorant of concurrency and found that when conditions are right, they occupy more than one CPU. I know that's not a very rigorous definition: I haven't explored this in depth yet.

But for those occasions when you really do need an explicit separate activity, one of Clojure's answers is apparently the agent.

(agent initial-state)

will create one. It's not like a Java Thread in terms of being a code block waiting to be executed. Instead, it's an activity waiting to be given work to do. You do this via

(send agent update-fn & args)

The example does

(def counter (agent 0))

counter is your name and handle for the agent; the agent's state is the number 0.

Having set that up, you can send work to the agent:

(send counter inc)

will tell it to apply the given function to its state.

You can later pull the state out of the agent by dereferencing it:

@counter will give you the current value of the number that started out at 0.

Function await will let you do something like a join on the agent's activity, should it be a long one:

(await & agents) will wait until they're all done; there's also another version that takes a timeout.

Carl Smotricz
+8  A: 

Clojure fns are Runnable so it's common to use them in exactly the way you posted, yes.

user=> (dotimes [i 10] (.start (Thread. (fn [] (println i)))))
0                                                             
1                                                             
2                                                             
4                                                             
5                                                             
3                                                             
6                                                             
7                                                             
8                                                             
9                                                             
nil

Another option is to use agents, in which case you would send or send-off and it'll use a Thread from a pool.

user=> (def a (agent 0))
#'user/a
user=> (dotimes [_ 10] (send a inc))
nil
;; ...later...
user=> @a
10

Yet another option would be pcalls and pmap. There's also future. They are all documented in the Clojure API.

Brian Carper
Ah, yes, the agent mechanism was something I ha forgotten about. Thanks!
andrewdotnich
Dont forget the likes of pmap!
Dan
+1  A: 

Using a future is usually the simplest adhoc access to threading. Depends entirely on what you want to do :)

Timothy Pratley