16 Stimmen

Wie kann ich einen ständig laufenden Hintergrundprozess in Clojure erstellen?

Wie kann ich einen ständig laufenden Hintergrundprozess in Clojure erstellen? Ist die Verwendung von "future" mit einer Schleife, die nie endet, der richtige Weg?

17voto

Alex Miller Punkte 67243

Sie könnten einfach einen Thread mit einer Funktion starten, die ewig läuft.

(defn forever []
  ;; do stuff in a loop forever
)

(.start (Thread. forever))

Wenn Sie nicht wollen, dass der Hintergrund-Thread das Beenden des Prozesses blockiert, müssen Sie ihn zu einem Daemon-Thread machen:

(doto 
   (Thread. forever)
   (.setDaemon true)
   (.start))

Wenn Sie etwas mehr Finesse wünschen, können Sie die Fabrik java.util.concurrent.Executors verwenden, um einen ExecutorService zu erstellen. Dies erleichtert die Erstellung von Thread-Pools, die Verwendung benutzerdefinierter Thread-Fabriken, benutzerdefinierter Eingangswarteschlangen usw.

El claypoole lib wickelt einen Teil der Arbeitsausführung in eine Clojure-freundlichere Api ein, falls Sie das anstreben.

7voto

mikera Punkte 103423

Meine einfache Endlosschleifenfunktion höherer Ordnung (mit Futures):

(def counter (atom 1))

(defn infinite-loop [function]   
  (function)
  (future (infinite-loop function))
  nil) 

;; note the nil above is necessary to avoid overflowing the stack with futures...

(infinite-loop 
  #(do 
     (Thread/sleep 1000) 
     (swap! counter inc)))

;; wait half a minute....

@counter
=> 31

Ich empfehle dringend, ein Atom oder einen der anderen Referenztypen von Clojure zu verwenden, um Ergebnisse zu speichern (wie beim Zähler im obigen Beispiel).

Mit ein wenig Feinschliff könnte man diesen Ansatz auch verwenden, um den Prozess auf eine thread-sichere Weise zu starten/stoppen/pausieren (z.B. ein Flag testen, um zu sehen, ob (Funktion) in jeder Iteration der Schleife ausgeführt werden soll).

2 Stimmen

P.s. auch schön zu wissen, dass der Overhead dieses Ansatzes ist ziemlich minimal - Sie können über eine Million Zähler Inkremente pro Sekunde zu erhalten, wenn Sie den Thread / schlafen entfernen

0 Stimmen

Eine weitere einfache Implementierung, die keinen Stack verbraucht (defn infinite [f seconds] (future (loop [] (f) (Thread/sleep (* seconds 1000)) (recur))))

0 Stimmen

@James - meine Implementierung verbraucht auch keinen Stack. Die Tatsache, dass der rekursive Aufruf von infinite-loop innerhalb einer Zukunft ist, bedeutet, dass sie nicht innerhalb des Stapelrahmens der ursprünglichen Funktion wiederkehrt.

1voto

Shantanu Kumar Punkte 1120

Vielleicht, oder vielleicht Lein-Daemon? https://github.com/arohner/lein-daemon

0 Stimmen

Ist es möglich, die Ausführung anzuhalten?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X