Académique Documents
Professionnel Documents
Culture Documents
IN CLOJURE
and (a few) other languages
A Quest
v 1.0
Michael Harrison
Capital Area Clojure Group
May 27, 2010
1
Fun Fact:
“Concurrent programming” means different things to
different people
“Multi-processor”
“Distributed”
“Parallel”
“Scalable”
2
Concurrent programming is not
a technology
a pattern
a methodology
3
Concurrent programming n. a quest to achieve
some perennial goals, by going beyond serial
execution on a single processor.
“I wanna go fast!”
4
There are many approaches to concurrency
• Collaborative multitasking
• Blackboard-style message-passing
5
What is asynchronous concurrency?
6
How’s it work in Clojure?
Clojure is built on the JVM.
It carefully uses Java’s thread pools and related
concurrency constructs.
7
How’s it work in Clojure?
Clojure is built on the JVM.
It carefully uses Java’s thread pools and related
concurrency constructs.
8
Clojure’s main players: agent and future
(def myfuture
(future (* 2 2)))
@future
(def impure-future
(future (my-side-effect-fn)
(* 2 2)))
9
Agent
Agents are an identity with a value (state).
(def myagent (agent 0))
You can create a new value from the old one, and
assign it to the identity, by sending the agent a
transforming function.
(send myagent inc)
(send-off myagent #(* 2 %))
Clojure’s Java
implementation may
change, of course, but
it’s worth knowing
the details.
11
clojure.lang.Agent
When send or send-off is applied to an agent and a
transforming function, an inner class Action is used.
static class Action implements Runnable{
void execute(){
try {
if(solo)
soloExecutor.execute(this);
else
pooledExecutor.execute(this);
}
...
12
clojure.lang.Agent
The action’s run method is invoked by the
Executor. It in turns calls a static doRun method:
static void doRun(Action action){
try {
...
try {
Object oldval = action.agent.state;
Object newval = action.fn.applyTo(
RT.cons(action.agent.state, action.args));
action.agent.setState(newval);
action.agent.notifyWatches(oldval,newval);
...
13
Future
Asynchronous computations occurring in other threads.
(def myfuture
(future (* 2 2)))
14
clojure.core/future-call
(future [body]) is a macro that wraps body as a
function of zero args to clojure.core/future-call
(defn future-call
...
[^Callable f]
(let [fut (.submit clojure.lang.Agent/soloExecutor f)]
(reify
clojure.lang.IDeref
(deref [_] (.get fut))
java.util.concurrent.Future
(get [_] (.get fut))
(get [_ timeout unit] (.get fut timeout unit))
(isCancelled [_] (.isCancelled fut))
(isDone [_] (.isDone fut))
(cancel [_ interrupt?] (.cancel fut interrupt?)))))
15
Agent vs. Future
Agent Future
may be repeatedly
may be evaluated only once
transformed
16
Examples: Agents
Because agents encapsulate state and may be
repeatedly transformed, they are good for running
(repeated) computations that some other process is
going to check on later (repeatedly).
17
Examples: Agents
Stuart Sierra’s “Agents of Swing” blog post
http://stuartsierra.com/2010/01/08/agents-of-swing
(defn new-flipper []
(agent {:total 0, :heads 0,
:running false,
:random (java.util.Random.)}))
18
Examples: Futures
19
Examples: Futures
pmap (as of Clojure 1.2)
(defn pmap
...
([f coll]
(let [n (+ 2 (.. Runtime getRuntime availableProcessors))
rets (map #(future (f %)) coll)
step (fn step [[x & xs :as vs] fs]
(lazy-seq
(if-let [s (seq fs)]
(cons (deref x) (step xs (rest s)))
(map deref vs))))]
(step rets (drop n rets))))
20
Advantage: Clojure
21
Another Way?
22
Another Way?
What if I could interleave executions, without
threading, so one could work while another blocked?
23
Evented IO Concurrency
24
Evented IO in JavaScript: Node.js
http://nodejs.org/
25
Evented IO in JavaScript: Node.js
var tcp = require('tcp');
var server = tcp.createServer(function (socket)
{
socket.setEncoding("utf8");
socket.addListener("connect", function () {
socket.write("hello\r\n");
});
socket.addListener("data", function (data) {
socket.write(data);
});
socket.addListener("end", function () {
socket.write("goodbye\r\n");
socket.end();
});
});
server.listen(7000, "localhost");
26
Distributed Computing with Tuple Spaces
A server maintains a “blackboard” of tuples, arrays of
mixed-type values.
27
Tuple Spaces in Ruby: Rinda
A one-sided conversation:
emitter process
while true
tuple_space.write [:message, gets]
end
receiver process
while true
puts tuple_space.take([:message, nil])[1]
end
http://jpz-log.info/archives/2007/10/11/ruby-fun-with-rinda/
28
Oodles more
29
Sir Not-Appearing-in-This-Film
30
Conclusions?
We aren’t there yet.
mh@michaelharrison.ws
@goodmike
If you’re interested in
what I know and like
the way I think, do get
in touch.
:->
32