Wishful Coding

Didn't you ever wish your
computer understood you?

Cooperative concurrency in Clojure

Today I had an interesting discussion about cheap preemptive threads in Clojure. Someone claimed Haskell can easily start 10.000 threads without getting slow, while Clojure - and native threads in general - do get slow after a couple of thousands.

After a discussion about Agents and thread pools, I proposed cooperative concurrency as a cheap solution. Cooperative concurrency isn't exactly preemptive, but it works. This is a for-fun implementation of trampoline using a hidden gem in Clojure called PersistentQueue.

Like trampoline, recursive functions return another function, which get called in a loop. Unlike trampoline, mine takes a seq of functions, puts them into a queue and executes the frontmost function, putting the result on the back of the queue.

Below is an example of the classic mutual recursive odd and even functions running in parallel, or alternating actually. Like pcalls, but on a single thread.

(ns cooperative)

(defn cooperative-tasks
  "Trampoline over a queue for
  cooperative multitasking"
  [fs]
  (if (not-any? fn? fs)
    fs
    (recur
      (doall (for [f fs]
        (if (fn? f)
          (f)
          f))))))


(comment
  (declare my-odd?)

  (defn my-even? [n]
    (if (zero? n)
      true
      #(my-odd? (dec (Math/abs n)))))

  (defn my-odd? [n]
    (if (zero? n)
      false
      #(my-even? (dec (Math/abs n)))))

  (cooperative-tasks [#(my-odd? 50009) #(my-odd? 50008) #(my-even? 50008) #(my-even? 50009)])
)