私は仕事の集まりを含む1つのref
を共有する100人の労働者(エージェント)を抱えています。このコレクションは、タスクを持っていますが、各ワーカーは(dosync
ブロックで)このコレクション、それを印刷し、時には(dosync
ブロックで)コレクションに戻ってそれを入れてから、一つのタスクを取得:clojure refの奇妙な振る舞い
(defn have-tasks?
[tasks]
(not (empty? @tasks)))
(defn get-task
[tasks]
(dosync
(let [task (first @tasks)]
(alter tasks rest)
task)))
(defn put-task
[tasks task]
(dosync (alter tasks conj task))
nil)
(defn worker
[& {:keys [tasks]}]
(agent {:tasks tasks}))
(defn worker-loop
[{:keys [tasks] :as state}]
(while (have-tasks? tasks)
(let [task (get-task tasks)]
(println "Task: " task)
(when (< (rand) 0.1)
(put-task tasks 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)
私はこのコードを実行し、エージェントによって印刷された最後の値は(複数回試行した後): 435445
, 4556294
1322061
3950017
です。 しかし、決して9999999
私は期待しています。 そして最後にコレクションが本当に空です。 私は間違っていますか?
編集:私はできるだけ単純労働者ループ書き直し
:
(defn worker-loop
[{:keys [tasks] :as state}]
(loop []
(when-let [task (get-task tasks)]
(println "Task: " task)
(recur)))
state)
をしかし、問題はまだそこにあります。 このコードは、唯一のワーカーを作成するときに期待どおりに動作します。
'println'はスレッドセーフですか? –
@ShannonSeveranceいいえ、読みやすいように_e.g._ like '(locking:out(println" ... "))'を使う必要があります。 –