When the last number in the range is reached, there still the old numbers are held by the workers. Some of them will be returned to the queue to be processed again.
To better see what happens, you can modify the worker-loop to print the last task processed by each worker:
(defn worker-loop [{:keys [tasks] :as state}] (loop [last-task nil] (if (have-tasks? tasks) (let [task (get-task tasks)] ;; (when (< (rand) 0.1) ;; (put-task tasks task) (recur task)) (when last-task (println "Last task:" last-task)))) state)
It also shows the race condition in code, where are the tasks that have-tasks? see have-tasks? are often accepted by others when get-task is called at the end of task processing.
Can race status be resolved by removing have-tasks? and instead using the nil return value from get-task as a signal that there are no more tasks available (for now).
Updated:
As already noted, the conditions of this race do not explain the problem.
Also, the problem is not solved by removing the possible race condition in get-task as follows:
(defn get-task [tasks] (dosync (first (alter tasks rest))))
However, changing the get-task to use explicit blocking seems to solve the problem:
(defn get-task [tasks] (locking :lock (dosync (let [task (first @tasks)] (alter tasks rest) task))))
Terje D.
source share