2015-09-14 7 views
6

Gibt es eine elegante Möglichkeit, einen laufenden Go-Block zu stoppen?Wie Stop Block in ClojureScript/core.async zu stoppen?

(ohne ein Flag Einbringen und verschmutzen den Code mit Kontrollen/branches)

(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

'(nah! Aufgabe)' vielleicht? - Google erstes Ergebnis. – birdspider

Antwort

4

Leider ist dies nicht möglich, mit core.async heute. Was Sie von der Erstellung eines go Blocks zurückbekommen, ist ein normaler Kanal, auf den das Ergebnis des Blocks angewendet wird, obwohl Sie dadurch keinen Zugriff auf den eigentlichen Block erhalten.

2

Wie in Arthur Antwort erwähnt, können Sie keinen go Block sofort beenden, aber Sie seit Ihrem Beispiel zeigen einen Multi-Phasen-Task (Teilaufgaben verwenden), ein Ansatz, wie dies funktionieren könnte :

(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))