В следующем коде я использую цикл go, который прослушивает канал и записывает прочитанные значения агенту. Затем в том же цикле функция записи в файл должна записывать каждый элемент агента в файл. Однако вывод в файл необычен, так как агент с [8 6 5 13] может передать свое содержимое в файл как 865n13. Если я удаляю вызов журнала в файл из функции регистратора и вызываю его отдельно, иногда вывод файла в порядке, иногда нет. Может ли кто-нибудь просто объяснить мне, что происходит, и, возможно, показать мне безопасный способ сделать это, демонстрирующий последовательное поведение? Я знаю, что отказ от использования агента, вероятно, был бы лучшим способом добиться согласованного поведения. Я просто хочу знать, в духе обучения, чего можно и чего нельзя достичь с помощью агентов. Заранее спасибо!
(defn log-to-file [file] (for [i (deref log)] (spit file (str "\n" i) :append true)))
(defn logger [file]
(go
(loop []
(when-let [v (<! print-chan)]
(send log conj v)
(log-to-file file)
(recur)))))
;; testing it out
(def log (agent []))
(>!! print-chan 5)
(logger "resources/test.txt")
(deref log)
РЕДАКТИРОВАТЬ:
Это код, переписанный с учетом комментариев в принятом ответе ниже. Я не рекомендую использовать этот код вообще, или, если на то пошло, когда-либо использовать агент в цикле go с побочными эффектами.
(def ch (chan))
(def a (agent []))
(defn double-async-print []
(go-loop []
(when-let [x (<! ch)]
(send a conj x)
(print (clojure.string/join "\n" @a)))
(recur)))
(go (doseq [n (range 10)] (>! ch n)))
(double-async-print)
;=>jsync 0.1.0-SNAPSHOT[stdout]:
00
10
1
20
1
2
30
1
2
3
40
1
...