2012-05-14 8 views
7

Sto cercando di capire i futuri del Clojure, e ho visto esempi dai libri Clojure comuni là fuori, e ci sono esempi in cui i futures sono usati per calcoli paralleli (che sembra avere un senso).future sul clojure

Tuttavia, spero che qualcuno possa spiegare il comportamento di un semplice esempio adattato dal libro Clojure Programming di O'Reilly.

(def long-calculation (future (apply + (range 1e8)))) 

Quando provo a dereferenziare questo, facendo

(time @long-calculation) 

Si restituisce il risultato corretto (4999,99995 mille miliardi), ma quasi istantaneamente (in 0.045 msec) sulla mia macchina.

Ma quando chiamo la funzione reale, in questo modo

(time (apply + (range 1e8))) 

ottengo il risultato corretto pure, ma il tempo impiegato è molto più grande (~ 5000 msec).

Quando decrescente il futuro, la mia comprensione è che viene creato un nuovo thread su cui viene valutata l'espressione - nel qual caso mi aspetterei che richieda anche circa 5000 msec.

Come mai il futuro senza referenze restituisce il risultato corretto così rapidamente?

risposta

11

Il calcolo in un futuro inizia non appena si crea il futuro (in un thread separato). Nel tuo caso, il calcolo inizia non appena si esegue (def long-calculation ....)

Dereferencing farà una delle due cose:

  • Se il futuro non ha completato, il blocco fino al completamento e quindi restituire il valore (questo potrebbe prendere una quantità arbitraria di tempo, o addirittura non completare mai se il futuro non riesce a terminare)
  • Se il futuro è stato completato, restituire il risultato. Questo è quasi istantanea (che è il motivo per cui si sta vedendo rendimenti dereferenziare molto veloce)

È possibile vedere l'effetto confrontando i seguenti:

;; dereference before future completes 
(let [f (future (Thread/sleep 1000))] 
    (time @f)) 
=> "Elapsed time: 999.46176 msecs" 

;; dereference after future completes 
(let [f (future (Thread/sleep 1000))] 
    (Thread/sleep 2000) 
    (time @f)) 
=> "Elapsed time: 0.039598 msecs" 
+0

C'è uno svantaggio di utilizzare un gran numero di futures? Ho scritto del codice che esegue calcoli numerici intensivi in ​​un numero di punti. Invece di usare matrici Java native o fare hint di tipo, posso semplicemente scrivere codice funzionale idiomatico e 'futuro 'invece i risultati di questi calcoli? – endbegin

+2

I futures sono abbastanza leggeri ma hanno un sovraccarico, quindi eviterei di usarli per calcoli estremamente piccoli. Se vuoi fare calcoli in parallelo, considera l'uso di 'pmap' - che è una versione simultanea di' map' che usa i futures sotto il cofano. Detto questo, se il tuo codice è davvero intensivo dal punto di vista numerico, probabilmente stai utilizzando al meglio sia gli array Java * che * pmap/futures se vuoi ottenere il massimo dal tuo tempo di CPU. – mikera

+0

Ho provato a giocare con pmap, ma l'ho trovato utile solo quando la dimensione dei dati è "grande" (quanto grande è in qualche modo soggettiva, ovviamente). Ho imparato Clojure implementando alcune semplici funzioni di elaborazione del segnale digitale, e c'è un notevole vantaggio in termini di velocità con l'utilizzo di matrici Java native su uno stile funzionale con l'astrazione seq in modalità singolo processore/thread. Se uso il futuro, l'accelerazione è così grande che non importa se utilizzo codice nativo o funzionale. Mi sento come se mi mancasse qualcosa di ovvio. – endbegin

Problemi correlati