2016-12-22 3 views
0

рассмотрим следующий код ядра-асинхронный. Она выводит строку «тик» каждые 2 секунд:Запуск и остановка core.async Интервал

(go-loop [] 
    (<! (timeout 2000)) 
    (prn "tick") 
    (recur)) 

Я ищу возможность для запуска и остановки интервала снаружи с помощью функций.

Единственное, что пришло мне на ум это:

(def running (atom false)) 

(defn start [] 
    (reset! running true) 
    (go (loop [] 
     (<! (timeout 2000)) 
     (prn "tick") 
     (when @running (recur))))) 

(defn stop [] 
    (reset! running false)) 

Является ли это путь? Или вы сделаете что-нибудь еще?

ответ

0

Вот что я хотел бы сделать:

(require '[clojure.core.async :as a]) 

(defn interval [f msecs] 
    (let [timing (a/chan) 
     kickoff 
     #(a/go 
      (a/<! (a/timeout msecs)) 
      (a/>! timing true))] 
    (a/go-loop [] 
     (when (a/<! timing) 
     (a/go (f)) 
     (kickoff) 
     (recur))) 
    (kickoff) 
    #(a/close! timing))) 

Пример:

(let [i (interval #(prn "tick") 2000)] 
    (Thread/sleep 7000) 
    (i)) 
;; "tick" 
;; "tick" 
;; "tick" 
;;=> nil 

Таким образом, все ваше состояние является локальным и обрабатывается через каналы и идут блоки, а не использовать глобальный атом. Поскольку работа, выполняемая на каждой итерации цикла, более или менее постоянна, ваше фактическое время интервала должно быть достаточно близко к числу msecs, которое вы проходите.

Или, если вы хотите гарантировать, что разные звонки на f выполняться в хронологическом порядке, вы могли бы сделать что-то вроде этого, вместо:

(require '[clojure.core.async :as a]) 

(defn interval [f msecs] 
    (let [action (a/chan (a/dropping-buffer 1)) 
     timing (a/chan) 
     kickoff 
     #(a/go 
      (a/<! (a/timeout msecs)) 
      (a/>! timing true))] 
    (a/go-loop [] 
     (when (a/<! action) 
     (f) 
     (recur))) 
    (a/go-loop [] 
     (if (a/<! timing) 
     (do 
      (a/>! action true) 
      (kickoff) 
      (recur)) 
     (a/close! action))) 
    (kickoff) 
    #(a/close! timing))) 

(использование этой функции тем же, что и в моей ранней interval функции.)

Здесь все вызовы f находятся в тот же цикл. Я использую dropping buffer, поэтому, если вызов f занимает больше времени, чем msecs, будущие звонки могут начать падать, чтобы идти в ногу.

0

Вот еще один способ, вы могли бы пойти

(defn start [] 
(let [ctl (chan 0)] 
    (go-loop [] 
    (alt! 
     (timeout 2000) (do 
        (prn "tick") 
        (recur)) 
     ctl (prn "Exit "))) 
    ctl)) 


(let [w (start) ] 
    (Thread/sleep 7000) 
    (>!! w "stop")) 

;;=>  "tick" 
     "tick" 
     "Exit"  

Вам не нужно определить состояние в пространстве имен. Функция Start возвращает chan для остановки в будущем.

Смежные вопросы