скажем, у меня есть канал out (chan)
. Мне нужно взять значения, которые помещаются в канал, и добавить их. Количество значений не определено (поэтому нельзя использовать традиционный цикл с конечным регистром (<! out)
) и исходит от внешнего ввода-вывода. Я использую фиксированный timeout
с alts!
, но это не лучший способ решения проблемы. На данный момент у меня есть следующее (которое я получил от https://gist.github.com/schaueho/5726a96641693dce3e47)
(go-loop
[[v ch] (alts! [out (timeout 1000)])
acc 0]
(if-not v
(do (close! out)
(deliver p acc))
(do
(>! task-ch (as/progress-tick))
(recur (alts! [out (timeout 1000)]) (+ acc v)))))
Проблема, с которой я столкнулся, заключается в том, что тайм-аута в 1000 иногда бывает недостаточно, и это приводит к преждевременному завершению цикла перехода (поскольку для завершения операции ввода-вывода и помещения значения в канал out
может потребоваться более 1000 мс). Я не думаю, что увеличение значения тайм-аута — хорошая идея, так как это может заставить меня ждать дольше, чем необходимо.
Каков наилучший способ гарантировать все операции чтения из выходного канала и правильный выход из цикла?
Обновление:
Почему я использую тайм-аут? Поскольку количество значений, помещаемых в канал, не является фиксированным; что означает, что я не могу создать случай выхода. Без случая выхода цикл перехода будет бесконечно ждать ((<! out)
) значений, которые будут помещены в выходной канал. Если у вас есть решение без тайм-аута, это было бы действительно здорово.
Как я узнаю, что прочитал последнее значение? Нет. Это проблема. Вот почему я использую тайм-аут и альт!! чтобы выйти из цикла.
Что вы хотите сделать с результатом? Простое добавление на данный момент. Однако это не главное.
Окончательное обновление:
Я нашел способ получить количество значений, с которыми я буду иметь дело. Поэтому я изменил свою логику, чтобы использовать это. Я все еще собираюсь использовать тайм-аут и альты! для предотвращения блокировки.
(go-loop
[[v _] (alts! [out (timeout 1000)])
i 0
acc 0]
(if (and v (not= n i))
(do
(>! task-ch (as/progress-tick))
(recur (alts! [out (timeout 1000)]) (inc i) (+ acc v)))
(do (close! out)
(deliver p* (if (= n i) acc nil)))))
alts!!
принимает вектор каналов и считывает значение из первой успешной операции канала. Если каналout
получает значения до истечения времени ожидания, я могу продолжить цикл. Если я получаю канал тайм-аута, это означает, что я могу выйти из цикла. Я не нашел другого способа выйти из цикла и, следовательно, мой вопрос. - person Lordking   schedule 15.02.2018(dotimes [v (<! out) i 1] ...)
и использоватьi
, чтобы определить, что я достиг конца. - person Lordking   schedule 15.02.2018