Enhebrar es probable que sea la solución más fácil, pero no es muy difícil de gestionar usted mismo en un solo hilo. Los entornos de "simulación" que solo le dan 100 ms a menudo no permiten ningún subproceso nuevo, por lo que esta es una alternativa.
La idea básica es crear un cierre que represente el trabajo que se debe realizar para finalizar la tarea, y devolverlo en lugar de un resultado si no tiene tiempo para terminar. Aquí hay un boceto: agrega una secuencia de números y se interrumpe cada diez operaciones en lugar de cada 100 ms.
(let [timer (atom 9)]
(defn keep-going? []
(not= 0 (swap! timer #(mod (inc %) 10)))))
(defn saving-addition [sum xs]
(if-let [[x & more] (seq xs)]
(let [next-thunk (fn [] (saving-addition (+ x sum) more))]
(if (keep-going?)
(next-thunk)
next-thunk))
sum))
(defn monitor [xs]
(loop [thunk (saving-addition 0 xs)]
(if (fn? thunk)
(do
(println "Saving execution state")
(recur (thunk)))
thunk)))
user> (monitor (range 25))
Saving execution state
Saving execution state
Saving execution state
300
Editar: Debido Clojure no tiene optimización de llamada, la creación de un golpe seco y luego llamando utiliza encima de la pila. Si, como es probable, puede ejecutar más de unos miles de pasos antes de que deba interrumpirse, obtendrá un desbordamiento de la pila. La única solución realista es duplicar el cuerpo del golpe seco, tanto en un recur
y en la continuación, como
(defn saving-addition [sum xs]
(if-let [[x & more] (seq xs)]
(let [sum (+ x sum)]
(if (keep-going?)
(recur sum more)
#(saving-addition sum more)))
sum))
que probablemente podría abstracta esto con una macro si tuviera que escribir varias funciones tales "suspendibles".
¿El árbol no está ordenado? Solo necesita encontrar algún elemento y devolver verdadero si lo obtiene, o necesita el camino también? – toto2