2015-09-14 3 views
6

Есть ли элегантный способ остановить бегущий блок?Как остановить блок go в ClojureScript/core.async?

(без введения флага и загрязняющих код с проверками/ветвями)

(ns example 
    (:require-macros [cljs.core.async.macros :refer [go]]) 
    (:require  [cljs.core.async  :refer [<! timeout]])) 

(defn some-long-task [] 
    (go 
    (println "entering") 

    ; some complex long-running task (e.g. fetching something via network) 
    (<! (timeout 1000)) 
    (<! (timeout 1000)) 
    (<! (timeout 1000)) 
    (<! (timeout 1000)) 

    (println "leaving"))) 

; run the task 
(def task (some-long-task)) 

; later, realize we no longer need the result and want to cancel it 
; (stop! task) 
+0

'(закрыть! Задача)' может быть? - первый результат Google. – birdspider

ответ

4

К сожалению, это невозможно с core.async сегодня. То, что вы получили от создания блока go, является обычным каналом, каков будет результат блока, хотя это не дает вам никакой обработки самому фактическому блоку.

2

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

(defn task-processor 
    "Takes an initial state value and number of tasks (fns). Puts tasks 
    on a work queue channel and then executes them in a go-loop, with 
    each task passed the current state. A task's return value is used as 
    input for next task. When all tasks are processed or queue has been 
    closed, places current result/state onto a result channel. To allow 
    nil values, result is wrapped in a map: 

    {:value state :complete? true/false} 

    This fn returns a map of {:queue queue-chan :result result-chan}" 
    [init & tasks] 
    (assert (pos? (count tasks))) 
    (let [queue (chan) 
     result (chan)] 
    (async/onto-chan queue tasks) 
    (go-loop [state init, i 0] 
     (if-let [task (<! queue)] 
     (recur (task state) (inc i)) 
     (do (prn "task queue finished/terminated") 
      (>! result {:value state :complete? (== i (count tasks))})))) 
    {:queue queue 
    :result result})) 

(defn dummy-task [x] (prn :task x) (Thread/sleep 1000) (inc x)) 

;; kick of tasks 
(def proc (apply task-processor 0 (repeat 100 dummy-task))) 

;; result handler 
(go 
    (let [res (<! (:result proc))] 
    (prn :final-result res))) 

;; to stop the queue after current task is complete 
;; in this example it might take up to an additional second 
;; for the terminated result to be delivered 
(close! (:queue proc))