Нужно ли помещать `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 может обрабатывать тысячи пользовательских потоков без проблем на современном оборудовании.

Другие вопросы по тегам