h3x3d
h3x3d

Reputation: 231

Clojure remove first(or last) element of vector inside ref

The thing i need - is simple queue, something, where i can put tasks, and retrieve them one-by-one from workers(without maintaining order of tasks).

I wrote something like this:

;; Definition
(def q (ref []))

;; Put
(defn put-in-queue [i]
  (dosync (alter q conj i)))

;; Get
(defn get-from-queue []
  (dosync
    (let [v (peek q)]
      (alter q pop)
      v)))

Is it correct solution? (maybe there are also better solutions for this task)

Upvotes: 2

Views: 1905

Answers (3)

Michał Marczyk
Michał Marczyk

Reputation: 84331

The correct solution is probably to use a java.util.concurrent queue, most likely java.util.concurrent.LinkedBlockingQueue. j.u.c queues are robust, perfectly suited to the task and work in Clojure just fine.

See my answer to the Producer consumer with qualifications SO question for a scenario with 5 producers, 2 consumers and a limited-size queue implemented in two ways for comparison: first with c.l.PersistentQueue, second with j.u.c.LinkedBlockingQueue.

Upvotes: 2

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91544

as dsm points out, when you need a queue, use a queue, and for times where you really need a vector and want to add things to the end and remove them from the front, subvec and conj are both O(1) functions on vectors.

user> (subvec [1 2 3] 1)
[2 3]
user> (conj [1 2 3] 4)
[1 2 3 4]
user> (-> [] (conj 1 2) (conj 3) (subvec 1))

Upvotes: 0

dsm
dsm

Reputation: 10403

You should use a clojure.lang.PersistentQueue, right tool for the job and all that :).

Sample below "borrowed" from Hidden features of Clojure:

user> (-> (clojure.lang.PersistentQueue/EMPTY)
          (conj 1 2 3)
          pop)
(2 3)

See the remainder of that answer for specifics.

Upvotes: 3

Related Questions