Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which is the ideal Clojure concurrency construct for maintaining queue of data to be processed?

Tags:

clojure

If I want to maintain a queue of frames of images on the server side that I will be sending to the client what data structure should I use ?

I am trying to make a simple app where I will send frames to the server and server will then push them to other clients.

should I maintain this queue as an atom or as a ref?

like image 902
Amogh Talpallikar Avatar asked Sep 13 '13 12:09

Amogh Talpallikar


People also ask

What is concurrency in Clojure?

Concurrency refers to a program's ability to carry out more than one task, and in Clojure you achieve this by placing tasks on separate threads. Programs execute in parallel when a computer has more than one CPU, which allows more than one thread to be executed at the same time.

Is clojure multithreaded?

Clojure simplifies multi-threaded programming in several ways. Because the core data structures are immutable, they can be shared readily between threads. However, it is often necessary to have state change in a program.


3 Answers

You could just use one of the queue classes from java.util.concurrent. Easy access to the Java standard library is after all one of the strong points of Clojure, so you don't have to build everything yourself from the building blocks provided by Clojure if Java already provides something that does the job.

I would suggest to choose something from the implementations of the interface BlockingQueue.

like image 99
Rörd Avatar answered Oct 21 '22 05:10

Rörd


The most important operation of a queue is popping items: namely getting-and-removing an item from the collection.

As this operation is composite, refs are more naturally suited to perform it atomically, this is - preventing race conditions (e.g. two threads getting the same item).

(defn remove-and-get [queue]
  (dosync
   (let [i (peek @queue)]
     (alter queue pop)
     i)))

(def q (ref (clojure.lang.PersistentQueue/EMPTY)))

(dosync
 (commute q conj 42)
 (commute q conj :foo)
 (commute q conj []))

[(seq @q) (remove-and-get q) (seq @q)]
;; evals to [(42 :foo []) 42 (:foo [])]

Equivalent functionality can be implemented in terms of atoms as well.

(defn remove-and-get [queue]
  (let [snapshot @queue
        i (peek snapshot)]
    (if (compare-and-set! queue snapshot (pop snapshot))
      i
      (recur queue))))

(def q (atom (clojure.lang.PersistentQueue/EMPTY)))

(swap! q conj 42)
(swap! q conj :foo)
(swap! q conj [])

[(seq @q) (remove-and-get q) (seq @q)]
like image 37
deprecated Avatar answered Oct 21 '22 03:10

deprecated


Seems to be a possibility for core.async.

like image 41
monoid Avatar answered Oct 21 '22 05:10

monoid