2011-03-13 12 views
15

¿Cuál es la forma idiomática de Clojure de crear un hilo que se repite haciendo actualizaciones a algunos refs compartidos y gestionar su duración? Me encuentro utilizando future para esto, pero parece un poco complicado ya que nunca devuelvo un valor significativo. Ej .:Idiomatic Clojure forma de generar y gestionar subprocesos de fondo

(future (loop [] (do 
    (Thread/sleep 100) 
    (dosync (...)) 
    (recur)))) 

Así mismo, tengo que tener cuidado de future-cancel esto cuando el procesamiento en segundo plano ya no es necesaria. Cualquier consejo sobre cómo orquestar eso en una aplicación Clojure/Swing sería agradable. P.ej. un dummy JComponent que se agrega a mi IU que es responsable de matar el hilo cuando la ventana está cerrada puede ser una idea.

Respuesta

8

No necesita un do en su bucle; está implícito. Además, aunque no hay nada de malo con una repetición de bucle incondicional, también puede usar (aunque sea verdadero ...).

future es una buena herramienta para esto; no dejes que te moleste que nunca recuperes un valor. Eso debería realmente te molesta si usas un agente en lugar de un futuro, sin embargo, los agentes sin valores son una locura.

Sin embargo, ¿quién dijo que necesita future-cancel? Solo haga uno de los pasos en su futuro para comprobar si todavía es necesario. Entonces, ninguna otra parte de su código necesita realizar un seguimiento de los futuros y decidir cuándo cancelarlos. Así que algo así como

(future (loop [] 
      (Thread/sleep 100) 
      (when (dosync 
       (alter some-value some-function)) 
      (recur)) ; quit if alter returns nil 
     )) 

sería un enfoque viable.

+0

Llamada 'futuro cancel' o la creación de una cantidad "cancele por favor" bandera a la misma cosa realmente. Todavía tengo que asegurarme de que suceda en el momento correcto y de manera robusta. (Extraño RAII) – pauldoo

+0

Tus otros puntos sobre 'do' y' while' son por supuesto correctos. :) – pauldoo

+0

No creo que dije que deberías establecer una bandera por favor-cancelar. Si su tarea en segundo plano se realizará después de, digamos, mil iteraciones o cuando la ventana se haya cerrado, el futuro puede rastrear esas cosas y apagarse. Algunas cosas son más complicadas y requieren una administración más detallada, y para aquellas que también podría usar el futuro cancelar. – amalloy

-1

El uso de agentes para el fondo tareas recurrentes parece más ordenado que me

(def my-ref (ref 0)) 

(def my-agent (agent nil)) 

(defn my-background-task [x] 
    (do 
    (send-off *agent* my-background-task) 
    (println (str "Before " @my-ref)) 
    (dosync (alter my-ref inc)) 
    (println "After " @my-ref) 
    (Thread/sleep 1000))) 

Ahora todo lo que tiene que hacer es iniciar el bucle

(send-off my-agent my-background-task) 

La función my-backgound-task está enviando sí al agente de llamada después de su invocación está hecha.

Esta es la manera cómo Rich Hickey realiza tareas recurrentes en la aplicación de ejemplo de colonias de hormigas: Clojure Concurrency

+0

Eso es una muy mala idea. La colonia de hormigas fue pre clojure 1.0. Él solo lo hizo así porque no había futuro. – nickik

+3

¿Por qué crees que es una mala idea? – Maciej

Cuestiones relacionadas