Нужно ли помещать `while true` внутри потока clojure core.async?
У меня есть шаблон производителя / потребителя, который я делал с core.async thread
функции так:
(defn -db-producer-factory [order-ids-chan next-chan]
(thread
(while true
(do
(let [order-id (<!! order-ids-chan)]
(condp = order-id
:finished (do
(>!! next-chan :finished))
(supress-w-nextexc
(->>
; get denorm'd order
(-> (r/-get-order :live order-id)
denorm/order->denormalized)
; put in a map to avoid nils
(hash-map :data)
(>!! next-chan)))))))))
Однако, когда я читаю документацию для thread
, это говорит:
Выполняет тело в другом потоке, немедленно возвращаясь к вызывающему потоку. Возвращает канал, который получит результат тела после завершения.
Похоже, его ожидаемый поток будет назван одноразовым; не то, что его построили для while
цикл внутри него.
Должен ли я не делать while true
в thread
блок? Или нить будет очищена, когда я закрою thread
результат чан?
2 ответа
Нить не будет очищена наверняка, так что, да, вероятно, вы не должны использовать while true
петля. Вместо этого вы можете использовать цикл с условием выхода.
Общий шаблон, чтобы сделать ваш go
-программы (проще говоря, циклы, которые выполняются в другом потоке) в зависимости от ваших входных каналов. Другими словами, когда канал, который предоставляет данные для go
-программа закрыта - go
-программа выключена.
Я немного переписал ваш код, возможно, что-то пропустил, но я надеюсь, что вы поймете:
(defn -db-producer-factory [order-ids-chan next-chan]
(go-loop [order-id (<! order-ids-chan)]
(condp = order-id
nil
;; exiting
nil
:finished (do
(>! next-chan :finished)
(recur (<! order-ids-chan)))
(do
(supress-w-nextexc
(->>
(-> (r/-get-order :live order-id)
denorm/order->denormalized)
(hash-map :data)
(>! next-chan)))
(recur (<! order-ids-chan))))))
Также я заменил thread
позвонить с go
вызов. Это "облегченная" версия thread
, который использует парковку потоков вместо блокировки собственных потоков. Если вам нужны потоки ОС, вы можете заменить их на (thread (loop ...
,
Пожалуйста, смотрите обсуждение здесь: http://www.braveclojure.com/core-async/
Самое важное предложение:
Причина, по которой вы должны использовать поток вместо блока go при выполнении длительной задачи, заключается в том, что вы не засоряете свой пул потоков.
Долгосрочные задачи - это как раз то, для чего созданы потоки Java. Поскольку у вас есть долгосрочное задание (кажется?), Оно должно иметь свой собственный поток.
JVM может обрабатывать тысячи пользовательских потоков без проблем на современном оборудовании.