Mam dwie różne funkcje na dwóch bardzo dużych zestawach danych, które muszą być przetwarzane, w końcu sprowadzając się do dwóch wartości logicznych. wartości te należy następnie połączyć w celu uzyskania końcowego wyniku. moje pytanie brzmi: jaki jest najlepszy sposób tworzenia wątków, aby dwie długie funkcje działały jednocześnie. moje myśli były czymś w rodzaju, ale szukałem informacji na temat lepszego sposobu, aby to osiągnąć.z Clojure gwintowanie długotrwałe procesy i porównywanie ich zwrotów
Odpowiedz
(podejście Obietnica oparte na górze, core.async podejście oparte niżej. Oba zwarcie na pierwszej wartości falsey.)
Oto wersja wykorzystująca fakt, że pojedyncza obietnica może zostać dostarczona wiele razy (chociaż tylko pierwsza dostawa może przynieść wartość; kolejne dostawy po prostu zwracają nil
bez efektów ubocznych).
(defn thread-and
"Computes logical conjunction of return values of fs, each of which
is called in a future. Short-circuits (cancelling the remaining
futures) on first falsey value."
[& fs]
(let [done (promise)
ret (atom true)
fps (promise)]
(deliver fps (doall (for [f fs]
(let [p (promise)]
[(future
(if-not (swap! ret #(and %1 %2) (f))
(deliver done true))
(locking fps
(deliver p true)
(when (every? realized? (map peek @fps))
(deliver done true))))
p]))))
@done
(doseq [[fut] @fps]
(future-cancel fut))
@ret))
Niektóre testy:
(thread-and (constantly true) (constantly true))
;;= true
(thread-and (constantly true) (constantly false))
;;= false
(every? false?
(repeatedly 100000
#(thread-and (constantly true) (constantly false))))
;;= true
;; prints :foo, but not :bar
(thread-and #(do (Thread/sleep 1000) (println :foo))
#(do (Thread/sleep 3000) (println :bar)))
Putting pomysły Artura i A. Webb wraz, można użyć do core.async i wyniki razem, gdy powrócił zwarcie na pierwszej wartości falsey :
(defn thread-and
"Call each of the fs on a separate thread. Return logical
conjunction of the results. Short-circuit (and cancel the calls
to remaining fs) on first falsey value returned."
[& fs]
(let [futs-and-cs
(doall (for [f fs]
(let [c (chan)]
[(future (>!! c (f))) c])))]
(loop [futs-and-cs futs-and-cs]
(if (seq futs-and-cs)
(let [[result c] (alts!! (map peek futs-and-cs))]
(if result
(recur (remove #(identical? (peek %) c)
futs-and-cs))
(do (doseq [fut (map first futs-and-cs)]
(future-cancel fut))
false)))
true))))
test z (constantly false)
i (constantly true)
:
(thread-and (constantly true) (constantly true))
;= true
(thread-and (constantly true) (constantly false))
;= false
;;; etc.
Należy również pamiętać, że zwarcie robi rzeczywiście praca:
;;; prints :foo before returning false
(thread-and #(do (Thread/sleep 3000) false)
#(do (Thread/sleep 1000) (println :foo)))
;;; does not print :foo
(thread-and #(do (Thread/sleep 3000) false)
#(do (Thread/sleep 7000) (println :foo)))
Dostępne również w tym [gist] (https://gist.github.com/michalmarczyk/5988137). –
Czy można to zrobić bez core.async? –
@event_jr: Właściwie to, po prostu zredagowano odpowiedź tak, aby zawierała podejście oparte na obietnicach. Dostępne również w tym [gist] (https://gist.github.com/michalmarczyk/5991353). –
Twoje podejście to dość normalny kod Clojure. Jeden inny wybór jest użycie obietnic lub jeśli potrzebujesz bardziej złożonego przetwarzania można rozważyć użycie coś jak lamina lub jeśli czujesz, jak życie na krawędzi krwawienia you could try core.async:
(ns async-example.core
(:require [clojure.core.async :refer :all])
(defn example []
(let [a (chan) ; a channel for a to report it's answer
b (chan) ; a channel for b to report it's answer
output (chan)] ; a channel for the reporter to report back to the repl
(go (<! (timeout (rand-int 1000))) ; process a
(>! a (rand-nth [true false])))
(go (<! (timeout (rand-int 1000))) ; process b
(>! b (rand-nth [true false])))
(go (>! output (and (<! a) (<! b)))) ; the reporter process
output)) ;return the channe that the result will be sent to
async-example.core> (<!! (go (<! (example))))
false
async-example.core> (<!! (go (<! (example))))
false
async-example.core> (<!! (go (<! (example))))
true
Oczywiście to przesada do sytuacji, choć to ogromnie zabawa i tak ;-)
Używanie 'Thread/sleep' w core.async code jest w pewnym sensie złem - pochłania pulę wątków śpiących. Natywna metoda core.async to zrobić z 'core.async/timeout', która zapali stan bloku na czas trwania. –
tak, to absolutnie poprawne, zmieniłem kod, aby używać limitu czasu. Dzięki za wskazanie, że –
- 1. Porównywanie zdań zgodnie z ich znaczeniem
- 2. Gwintowanie OpenMP i MKL
- 3. Wiązania NamedScopes i asynchronizacja (gwintowanie)
- 4. Java Generics i typy zwrotów
- 5. Bezpiecznie zatrzymaj długotrwałe zadanie
- 6. Gwintowanie w Ruby z limitem
- 7. Procesy i połączenia MySQL
- 8. Podstawowe pojęcia JDBC, łączenie i gwintowanie
- 9. C# Gwintowanie - Jak uruchamiać i zatrzymywać wątek
- 10. Porównywanie Common Lisp z Gambit w.r.t ich dostępu do bibliotek i systemów obiektowych
- 11. Gwintowanie WPF C#
- 12. Funkcje wywoływania zwrotów i rekursja JavaScript
- 13. Wykrywanie i porównywanie twarzy
- 14. Porównywanie druida i pipelinedb
- 15. gwintowanie wektora funkcji
- 16. Jak mogę sprawdzić, jakie procesy działają na zdalnym serwerze Ubuntu i ich zabić?
- 17. fork() procesy podrzędne i nadrzędne
- 18. Przechowywanie i porównywanie obiektów z bazy danych
- 19. Klasyfikuj procesy węzłowe razem z MPI i FORTRAN
- 20. C# Gwintowanie: Ćwiczenia dla początkujących
- 21. funkcja przesłaniania z różnymi typami zwrotów
- 22. Lista zwrotów z metody async/await
- 23. Porównywanie plików backbone.js i Dojo
- 24. Porównywanie i uwierzytelnianiu struktury danych
- 25. Czy atomowy jest zamek (gwintowanie)?
- 26. Monitor zatrzymał procesy pythonowe
- 27. Porównywanie ciąg i logiczną w języku Expression
- 28. Porównywanie ciągów i tablic C#
- 29. Rozwidlenie/procesy wielogatkowe | Bash
- 30. Solr - Bliskość wyszukiwania używając zwrotów
Czy takie podejście nie działa? Czy masz z tym jakiś szczególny problem? Wydaje mi się całkiem nieźle :) –
podczas pracy, musiał zakończyć oba bez zwarcia, jeśli się nie udało. Szukałem szybszego sposobu robienia tego samego. – ChadJPetersen
@ChadJPetersen Nie, nie musi kończyć obu; '' i 'zwarcia. Nie oznacza to, że go nie używa, ale jest to oddzielna troska (i możesz go anulować, jeśli chcesz). –