2016-05-03 11 views
4

Ich habe diese Erzeuger/Verbraucher-Muster i wie so mit core.async thread Funktionen machen habe:Sollte man `while true` in einen clojure core.async-Thread einfügen?

(defn -db-producer-factory [order-ids-chan next-chan] 
    (thread 
    (while true 
     (do 
     (let [order-id (<!! order-ids-chan)] 
      (condp = order-id 
      :finished (do 
         (>!! next-chan :finished)) 
      (supress-w-nextexc 
       (->> 
       ; get denorm'd order 
       (-> (r/-get-order :live order-id) 
        denorm/order->denormalized) 
       ; put in a map to avoid nils 
       (hash-map :data) 
       (>!! next-chan))))))))) 

jedoch, wenn ich the documentation für thread lesen, heißt es:

den Körper Führt in einem anderen Thread, der sofort zum aufrufenden Thread zurückkehrt. Gibt einen Kanal zurück, der nach Fertigstellung das Ergebnis des Körpers erhält.

Es hört sich an wie sein erwarteter Thread einmal genannt wird; nicht, dass es für eine while Schleife darin gebaut wurde.

Sollte ich nicht while true in einem thread Block tun? Oder wird der Thread aufgeräumt, wenn ich das thread Ergebnis chan schließe?

Antwort

1

Der Thread wird nicht sicher gereinigt werden, ja, wahrscheinlich sollten Sie nicht while true Schleife verwenden. Stattdessen können Sie eine Schleife mit Exit-Bedingung verwenden.

Gemeinsame Muster sind Ihre go-Routinen (einfach gesagt, Schleifen, die auf anderen Thread ausgeführt werden) abhängig von Ihren Eingabekanälen. Mit anderen Worten, wenn der Kanal, der die Daten an die go-Routine liefert, geschlossen ist - go - wird die Routine heruntergefahren.

Ich habe Ihren Code ein wenig umgeschrieben, wahrscheinlich verpasst etwas, aber ich hoffe, dass Sie auf die Idee kommen:

(defn -db-producer-factory [order-ids-chan next-chan] 
    (go-loop [order-id (<! order-ids-chan)] 
    (condp = order-id 

     nil 
     ;; exiting 
     nil 

     :finished (do 
        (>! next-chan :finished) 
        (recur (<! order-ids-chan))) 
     (do 
     (supress-w-nextexc 
     (->> 
      (-> (r/-get-order :live order-id) 
       denorm/order->denormalized) 
      (hash-map :data) 
      (>! next-chan))) 
     (recur (<! order-ids-chan)))))) 

Auch habe ich thread Anruf mit go Anruf ersetzt. Dies ist eine "Lightweight" -Version von thread, die Thread-Parken verwendet, anstatt den nativen Thread zu blockieren. Wenn Sie OS-Threads benötigen, können Sie sie durch (thread (loop ... ersetzen.

+0

Ich habe eine harte Zeit zu glauben, dass die 'loop' innerhalb' thread' entsorgt werden könnte/deallocated/garbage collected, aber Sie haben meine Frage beantwortet! – Micah

+0

hat es für mich in clojure # Core-async Schlafraum aufgeräumt. Vielen Dank! – Micah

0

Bitte beachten Sie die Diskussion hier: http://www.braveclojure.com/core-async/

Der wichtigste Satz ist:

Der Grund, warum Sie Gewinde anstelle eines Go-Block verwenden sollten, wenn Sie Durchführung eine lang andauernde Aufgabe sind, ist damit du deinen Thread Pool nicht verstopfst.

Lang laufende Aufgaben sind genau das, wofür Java-Threads gemacht werden. Da Sie eine lange laufende Aufgabe haben (es scheint?), Sollte es einen eigenen Thread haben.

Die JVM kann tausend Benutzer Threads ohne Problem auf moderner Hardware verarbeiten.

+1

Die Frage bestand nicht darin, einen lang laufenden Thread zu haben. Es ging darum, einen lang laufenden Thread zu haben, der auch dann noch lief, wenn er nicht mehr benötigt wurde, was zu einem Speicherverlust führen konnte. –