2015-05-20 13 views
5

Da http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/:blocco Go vs thread nel core.async

Per ottenere un po 'più concreto vediamo cosa succede quando cerchiamo di emettere qualche richiesta GET HTTP usando core.async. Iniziamo con la soluzione ingenua , utilizzando l'IO di blocco tramite clj-http.

(defn blocking-get [url] 
    (clj-http.client/get url)) 


(time 
    (def data 
    (let [c (chan) 
      res (atom [])] 
     ;; fetch em all 
     (doseq [i (range 10 100)] 
     (go (>! c (blocking-get (format "http://fssnip.net/%d" i))))) 
     ;; gather results 
     (doseq [_ (range 10 100)] 
     (swap! res conj (<!! c))) 
     @res 
     ))) 

Qui stiamo cercando di recuperare 90 frammenti di codice (in parallelo) utilizzando andare blocchi (e bloccando IO). Questo ha richiesto molto tempo, e questo perché i thread del blocco go sono "bloccati" dalle operazioni di I/O con esecuzione lunga. La situazione può essere migliorata passando i blocchi go ai normali thread .

(time 
    (def data-thread 
    (let [c (chan) 
      res (atom [])] 
     ;; fetch em all 
     (doseq [i (range 10 100)] 
     (thread (>!! c (blocking-get (format "http://fssnip.net/%d" i))))) 
     ;; gather results 
     (doseq [_ (range 10 100)] 
     (swap! res conj (<!! c))) 
     @res 
     ))) 

Che cosa significa che "vanno discussioni blocco sono accaparrati dai lunghi in esecuzione operazioni di IO"?

risposta

4

I blocchi di partenza sono concepiti come una sorta di fili cooperativi leggeri; forniscono un comportamento simile a thread con un sovraccarico minore rispetto ai thread JVM completi utilizzando alcuni thread in un pool e il passaggio dei blocchi di go quando sono parcheggia - ad esempio, quando si attende su un canale utilizzando <!. La commutazione dei thread non può funzionare quando si chiama un metodo nel blocco che blocca il thread JVM, quindi si esauriscono rapidamente i thread JVM. La maggior parte delle operazioni IO standard di Java (e Clojure) bloccheranno il thread corrente durante l'attesa.

+0

Anche se il clojure userebbe ForkJoin ma sembra che non lo sia. Usa un semplice FixedThreadpool. C'è una ragione per questo? Scala forkjoins e può anche dire all'esecutore che sta bloccando il codice in modo da consigliare di generare più thread. (http://docs.scala-lang.org/overviews/core/futures.html) e (http://dev.clojure.org/display/design/Async+Executor) – ClojureMostly

2

Che cosa significa che "i thread di blocco go vengono bloccati dalle operazioni di I/O in esecuzione"?

Ci sono un numero limitato di thread dedicati alla pubblicazione di blocchi di go *. Se si esegue un'operazione di I/O di blocco su uno di questi thread, non può essere utilizzato per nessun altro scopo fino a quando l'operazione non viene completata (a meno che il thread non venga interrotto). Ciò vale anche per i thread di blocco non-go (cioè i thread che vengono restituiti dalla funzione thread), ma i thread di blocco non-go non provengono dal pool di thread del blocco go limitato. Quindi, se blocchi I/O in un blocco go, stai "hogando" che il thread del blocco viene utilizzato da altri blocchi go, anche se il thread non sta facendo alcun lavoro effettivo (è solo in attesa dell'ingresso/uscita funzionamento).

* Il numero attualmente è 42 + il numero di processori disponibili per JVM.

+0

Ci scusiamo per questo, ma non lo è t it 2 + processori disponibili? Non 42 + ...? – Carcigenicate

+0

Il pool di thread di go-block per processo o per-JVM o per macchina? – tar

+0

Qual è la differenza tra per-process e per-JVM? – erikprice