2016-11-15 3 views
2

Ich habe einen Kanal, in dem ich Werte in eine doseq-Schleife setze.Wie kann ich einen Vektor zurückgeben?

Dieser Code aus einer Liste von ISBN-Nummern liest und für jede ISBN-Nummer, funktioniert ein amazon Suche Inhalt eines Buches zurückzukehren, und ruft dann eine andere Funktion, um den Titel und Rang zu erhalten

(def book_channel (chan 10)) 
+0

Schließen Sie book_channel irgendwo? –

+0

Wo würde (close! Book_channel) gehen? Ich bin verwirrt. – lalakers4life

+0

Sie sollten schließen! der book_channel, nachdem du doseq beendet hast – rmcv

Antwort

1

Sie müssen irgendeine Art von Koordination tun, um zu bestimmen, wann alle Ihre Arbeit beendet ist . Sie können, dass die Koordination ziehen ziemlich leicht in den Haupt-Thread aus:

(def book_channel (chan 10)) 
(defn concurrency_test 
    [list_of_isbns] 
    (doseq [isbn list_of_isbns] 
    (go (>! book_channel 
      (get_title_and_rank_for_one_isbn 
       (amazon_search isbn))))) 
    (prn (loop [results []] 
       (if (= (count results) (count list_of_isbns)) 
        results 
        (recur (conj results (<!! book_channel))))))) 

Hier habe ich eine Schleife verwendet, die für die Ergebnisse immer wieder warten und das Hinzufügen von ihnen zu dem Vektor, bis wir so viele Ergebnisse haben, wie wir ISBN-Nummern zu tun. Sie sollten sicherstellen, dass get_title_and_rank_for_one_isbn immer ein Ergebnis erzeugt, das auf einen Kanal gesetzt werden kann, andernfalls wartet die Schleife für immer.

+0

Sie löste alle meine Probleme .. Vielen Dank – lalakers4life

+0

es funktioniert perfekt – lalakers4life

+0

Können Sie ein wenig erklären, was die Schleife Teil tut? Vor allem die Zählung ergibt einen Teil. – lalakers4life

2

stellen Sie sicher, Sie verwenden clojure.core.async/into statt clojure.core/into. Hier ist ein Beispiel für eine Hin- und Rückfahrt von der Sammlung zu kanalisieren und zurück zur Kollektion:

user> (require '[clojure.core.async :as async :refer [<! <!! >!! >! chan go]]) 
nil 

user> (def book-chan (async/to-chan [:book1 :book2 :book3])) 
#'user/book-chan 

user> (<!! (clojure.core.async/into [] book-chan)) 
[:book1 :book2 :book3] 

clojure.core.async/into gibt einen Kanal, der genau ein Element, um es geschrieben haben. Dieses eine Element wird geschrieben, sobald der Eingangskanal geschlossen ist. Dies hält die ganze Sache asynchron und es erfordert, dass der Code, der Dinge in den Buchkanal legt, den Chan schließt, um zu signalisieren, dass alle Bücher da sind.

+0

gut der Fehler ist jetzt weg. Aber jetzt drucke ich einen leeren Vektor – lalakers4life

+0

, der fast immer bedeutet, dass der Code, der das Ergebnis in den Chan setzen würde, eine Ausnahme auslöst. Sie feuern alle Anfragen parallel ab, was zu Rate-Limit-Ausnahmen führt, sobald Sie diese in der Produktion bekommen und beginnen, sie auf größeren Listen auszuführen. Es empfiehlt sich, sie in einer kleinen Anzahl von Batches zu verwenden, bei denen jeder Aufruf in einem Stapel erfolgt, nachdem der vorherige Aufruf von diesem Stapel beendet wurde. und legen Sie eine Verzögerung zwischen jedem Anruf fest. Wenn Sie Emacs verwenden, suchen Sie in den Puffernamen * nrepl-server Ihr-Projektname * für den Fehler (es ist nicht in der Standardpufferliste, müssen Sie den Namen eingeben) –

1

Sie sollten schließen! der book_channel, nachdem du es fertig gemacht hast, etwas hineinzuschieben. Per async/in Dokumentation - "ch muss zuvor schließen, um ein Ergebnis zu erzeugen."

(let [book> (chan)] 
    (go 
    (doseq [e (range 8)] 
     (>! book> e)) 
    (close! book>)) 
    (<!! (async/into [] book>))) 

Alternativ können Sie async/onto-chan benutzen, die den Kanal für Sie schließt:

(let [book> (chan)] 
    (async/onto-chan book> (range 8)) 
    (<!! (async/into [] book>))) 
+0

das Problem mit diesem Ansatz ist, dass es nur gibt einen gehen, den ganzen Job zu machen. Ich musste in doseq gehen, damit mehrere Go's mit einer anderen ISBN umgehen können. – lalakers4life

+0

Die Nummer des "Go" -Blocks spielt keine Rolle, solange Sie wissen, wann async/into das Endergebnis produzieren kann. Wenn Sie onto-chan verwenden, wird es automatisch geschlossen! der Kanal, wenn alle Artikel kopiert werden. Wenn Sie "go" -Block benötigen, um die Arbeit auf koordinierte Weise zu parallelisieren, sollten Sie die Pipeline-Funktionen übernehmen. Siehe meine andere Antwort [hier] (http://stackoverflow.com/a/40615396/6013799) – rmcv

Verwandte Themen