Предотвратить завершение программы во время бесконечного выполнения блоков go?

Я написал автономный uberjar с основным методом, который запускает два блока go следующим образом:

(defn -main [& args]
  (let [c (chan)]
    (go (while true
           (>! c (rand))))
    (go (while true
           (<! c)))))

Но когда я запускаю программу, она быстро завершается. Почему? Мое намерение состоит в том, чтобы блоки go выполнялись бесконечно. в итоге я застрял

 (<!! (chan))

в конце основной функции, чтобы предотвратить завершение. Есть ли лучший способ сделать это?


person AustinC    schedule 11.01.2014    source источник
comment
Значит, нет никакого способа чисто выйти из вашего приложения?   -  person Shepmaster    schedule 12.01.2014
comment
Я полагаюсь на Ctrl+C.   -  person AustinC    schedule 12.01.2014
comment
@AustinC: Это именно ваша проблема. Когда вы проектируете асинхронные потоки данных с бесконечными циклами диспетчеризации, вам нужны собственные условия отмены. В core.async отмена обычно передается от производителя к потребителю путем вызова close! на стороне производителя, а затем отправки nil на стороне потребителя. Вот пример кода: refheap.com/21103   -  person Leon Grapenthin    schedule 12.01.2014


Ответы (1)


Программа завершается, потому что после создания этих go блоков основная функция завершается. От нечего делать он выходит; это не должно быть большим сюрпризом. Конечно, мы бы предпочли, чтобы основное приложение продолжало работать, пока все эти go блоки все еще живы.

Каждый из этих go блоков создает канал; вы можете подождать, пока один из них что-то вернет (хотя в нынешнем виде они никогда этого не сделают). Попробуйте заблокировать с помощью alts!! во время вращения:

(defn -main
  [& args]
  (let [c (chan)]
    (alts!!
      [(go (while true
             (>! c (rand))))
       (go (while true
             (<! c)))])))

Таким образом, ваш основной поток будет блокироваться до тех пор, пока один из каналов в alts!! не вернет значение. Прямо сейчас он заблокируется навсегда, но эта структура настраивает вас на более интересные вещи. Например, вы можете выйти из приложения, когда случайное значение превысит некоторый порог:

(defn -main
  [& args]
  (let [c (chan)]
    (alts!!
      [(go (while true
             (>! c (rand))))
       (go-loop [value (<! c)]
                (if (> value 0.8)
                  value ; return value from the go block
                  (recur (<! c))))])))

Или, сходите с ума, тайм-аут через секунду:

(defn -main
  [& args]
  (let [c (chan)]
    (alts!!
      [(go (while true
             (>! c (rand))))
       (go (while true
             (<! c)))
       (timeout 1000)])))

Более важный вывод заключается в том, что есть большая вероятность, что вы захотите заблокировать свой основной поток, чтобы дождаться, пока эти асинхронные go блоки закончат свою работу.

person Beyamor    schedule 12.01.2014