Clojure example from „The Joy Of Clojure“ parallelized

I am currently reading „The Joy Of Clojure“ by Michael Fogus and Chris Houser – a great book to see the „why“ behind the clojure way. You should have had a look into clojure before and be willing to read a lot of docs besides the book.

In the book there is a simple example program to display a nice graphic, created by applying xor to the pixel coordinates and using them as grayscale color value. The chapter is „Using the REPL to experiment“.
While reading this part, I thought it would be nice to have that algorithm for parallel processing and experimented a little bit.

The following listing is the result, it modified the original and uses simple threading and the „locking“ macro. It is also interesting to see what happens if you leave out the synchronizing between setting the color and drawing the pixel, as you can see in the screenshots. I hope the original author is okay with using his examples.

Simply paste it to your REPL and try it out.

(defn
  ^{:doc "Calculate the color for a coordinate x and y by applying the given
function. Offset and max values can be specified as input." }
  f-valueso [f xoffset xmax yoffset ymax]
  (for [x (range xoffset xmax) y (range yoffset ymax)
          :let [v (rem (f x y) 256)]]
    [x y (if (< v 0) (* -1 v) v)]
  )
)

(defn
  ^{:doc "Devides the given value in 'parts' equal parts. For
example 200 2 will become [[0 100] [100 200]]"}
  from-to-parts [value parts]
  (loop [
    steps (conj (vec (range 0 value (int (/ value parts)))) value)
    result []
    ]
    (if (seq (rest steps))
      (recur (rest steps) (conj result [(first steps) (second steps)]))
      result
    )
  )
)

; Initialize the frame
(def frame (java.awt.Frame.))
(.setVisible frame true)
(.setSize frame (java.awt.Dimension. 256 256))
(.setLocation frame 300 300)
; Graphics size is only as big as the frame was at getGraphics times
; (that had cost me some time ...)
(def gfx (.getGraphics frame))

(defn clear
  ([g] (.clearRect g 0 0 256 256))
  ([g x y] (.clearRect g 0 0 x y))
)

(defn
  ^{:doc "Draw the picture in a specified area using the color function."}
  draw-part [gfx f xoffset xmax yoffset ymax]
  (doseq [[x y v] (f-valueso f xoffset xmax yoffset ymax)]
;    (Thread/sleep 1) Uncomment this if it draws too fast
    (locking gfx
      (.setColor gfx (java.awt.Color. v v v))
      (.fillRect gfx x y 1 1)
    )
  )
)

(defn
    ^{:doc "Draw a picture to 'gfx' that is created by using the
given color function. Use 'n' threads to create the picture from
0 to x/y max"}
  draw-valuesp [f xmax ymax n]
  (clear gfx)
  (.setSize frame (java.awt.Dimension. xmax ymax))
  (def gfx (.getGraphics frame))
  (clear gfx xmax ymax)
  (doseq [
    [xoffset xmax] (from-to-parts xmax n)
    [yoffset ymax] (from-to-parts ymax n)
  ]
    (.start (Thread. 
      #(draw-part gfx f xoffset xmax yoffset ymax)
    ))
  )
)

(draw-valuesp bit-xor 256 256 3)

The result:

Multithreaded version during processing:

Result without synchronization:

I am aware that there is not much concurrency in the problem and it is not the greatest example to show the power of clojure’s capabilities. But that wasn’t the point of it.

2 Responses to Clojure example from „The Joy Of Clojure“ parallelized

  1. micha sagt:

    I’ve got a feeling that you’re going to implement Pachisi in Clojure :)

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: