Here is working example code demonstrating how you might do this without 
agents:

(in-ns 'user)

(def tasks (ref (into clojure.lang.PersistentQueue/EMPTY (range 1 1000))))

(defn get-task
  [tasks]
  (dosync
    (let [task (first @tasks)]
      (alter tasks pop)
      task)))

(defn worker-loop
  []
  (loop [completed-tasks []]
    (if-let [task (get-task tasks)]
      (recur (conj completed-tasks task))
      completed-tasks)))

(defn create-workers
  [n & options]
  (vec (repeatedly n (fn []
                       (future
                         (worker-loop))))))

(def workers
  (create-workers 100))

(defn worker-test
  [xs]
  (= (set (mapcat deref workers))
     (set xs)))

(worker-test (range 1 1000))

On Tuesday, August 23, 2016 at 9:09:31 AM UTC-4, adrian...@mail.yu.edu 
wrote:
>
> I haven't run your code yet, but it's bad form to use Clojure's reference 
> types inside other reference types. They should store persistent data 
> structures to really make any sense in a concurrent context. 
>
> On Tuesday, August 23, 2016 at 8:22:00 AM UTC-4, Sergei Koledov wrote:
>>
>> Hello,
>>
>> I had a problem when I run the following code:
>>
>> (defn get-task [tasks]
>>   (dosync
>>     (let [task (first @tasks)]
>>       (alter tasks rest)
>>       task)))
>>
>> (defn worker [& {:keys [tasks]}]
>>   (agent {:tasks tasks}))
>>
>> (defn worker-loop [{:keys [tasks] :as state}]
>>   (loop [last-task nil]
>>     (if-let [task (get-task tasks)]
>>       (recur task)
>>       (locking :out (println "Last task: " last-task))))
>>   state)
>>
>> (defn create-workers [count & options]
>>   (->> (range 0 count)
>>        (map (fn [_] (apply worker options)))
>>        (into [])))
>>
>> (defn start-workers [workers]
>>   (doseq [worker workers] (send-off worker worker-loop)))
>>
>> (def tasks (ref (range 1 10000000)))
>>
>> (def workers (create-workers 100 :tasks tasks))
>>
>> (start-workers workers)
>> (apply await workers)
>>
>> Description: I have several agents (100 in my case). Each agent running 
>> in a separate thread. All agents share the one ref with the collection of 
>> tasks (range of longs in my case). Each agent get tasks from the collection 
>> (in transaction) one by one until the collection becomes empty and then 
>> prints the last task which it handle. However, when I run this code it 
>> looks like the collection of tasks suddenly becomes empty and workers 
>> handle only portion of all tasks (average 25-40% of all number).
>>
>> This code behave as I expected, when I create only one agent or use 
>> explicit locking in get-task function:
>>
>> (defn get-task [tasks]
>>   (locking :lock
>>     (dosync
>>     (let [task (first @tasks)]
>>       (alter tasks rest)
>>       task))))
>>
>> I run this code on the Clojure 1.8.0
>> java version "1.8.0_91"
>> Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
>> Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
>>
>> Can anyone tell me, what am I doing wrong, or it really looks like a bug 
>> in the clojure STM?
>> I already asked this question on stackoverflow.com (
>> http://stackoverflow.com/questions/39054911/strange-behavior-of-clojure-ref),
>>  
>> but so far nobody has been able to help me.
>>
>> P.S. Sorry for my english skill.
>>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to