2013-10-30 18 views
18

Sto cercando di capire l'idea e lo scopo del pacchetto concorrente scalaz, principalmente classi Future e Task, ma quando li uso in alcune applicazioni, è lontano dall'analogico sequenziale semplice, mentre scala.concurrent.Future, funziona più che meglio. Qualcuno può condividere con la sua esperienza sulla scrittura di un'applicazione concorrente/asincrona con scalaz, in pratica come usare il suo metodo async correttamente? Come ho capito dalle fonti async non utilizza un thread separato come la chiamata ai metodi standard future o fork/apply da scalaz, quindi perché è chiamato async quindi? Significa che per ottenere una reale concorrenza con lo scalaz devo sempre chiamare fork(now(...)) o apply?Un piccolo aiuto per la comprensione di Scalaz Future e Task

risposta

17

Non sono un esperto di scalaz, ma cercherò di aiutarti un po '. Lasciatemi rispondere alle tue domande una per una:

1) Qualcuno può condividere con la sua esperienza sulla scrittura di applicazioni concorrenti/asincrone con scalaz, in pratica come utilizzare il suo metodo asincrono correttamente?

di prima dare un'occhiata al async firma Let:

def async[A](listen: (A => Unit) => Unit): Future[A]

Questo potrebbe essere un po 'criptico in un primo momento, quindi come sempre è buona idea di guardare al test per comprendere i possibili casi d'uso. In https://github.com/scalaz/scalaz/blob/scalaz-seven/tests/src/test/scala/scalaz/concurrent/FutureTest.scala è possibile trovare il seguente codice:

"when constructed from Future.async" ! prop{(n: Int) => 
    def callback(call: Int => Unit): Unit = call(n) 
    Future.async(callback).run must_== 
} 

Come sappiamo dalla firma Future.async solo costruire nuove futuro usando la funzione della firma (A => Unit) => Unit. Ciò che questo significa in realtà è che Future.async assume come funzione di parametro che per il callback dato esegue tutti i calcoli necessari e passa il risultato a tale callback.
È importante notare che Future.async non esegue alcun calcolo su se stesso, prepara solo la struttura per eseguirli in un secondo momento.

2) Come ho capito dal codice sorgente async non utilizza un thread separato come la chiamata al futuro standard, o i metodi fork/apply da scalaz funziona, quindi perché è chiamato async, quindi?

Sei corretto. Solo fork e apply sembra che stia eseguendo qualcosa usando i thread, il che è facile notare guardando le firme che contengono implicit pool: ExecutorService. Non posso parlare per gli autori qui, ma suppongo che async sia correlato al callback. Significa che piuttosto che bloccare su Future per ottenerlo risultato alla fine utilizzerai la callback asincrona.

3) Significa che per ottenere una reale concorrenza con lo scalaz devo sempre chiamare fork (ora (...)) o applicare?

Da quello che posso dire, sì. Basta notare che quando crei Future usando la sintassi Future(x) stai usando il metodo apply qui, quindi questo è un tipo di comportamento predefinito (che va bene).

Se si desidera comprendere meglio il design di Scalaz Futures, posso consigliarti di leggere "Functional Programming in Scala". Credo che questo libro sia scritto dai principali contributori Scalaz e il capitolo 7 discute la progettazione dell'API per la libreria di parallelismo puramente funzionale. Non è esattamente lo stesso di Scalaz Future, ma puoi vedere molte somiglianze.

2

Si può anche leggere il meraviglioso Timothy Perrett blog post su Scalaz Task and Future che copre molti dettagli non così ovvi.

1

async per poter adattare un asincrona API callback basata come Future. Si chiama async perché è previsto che venga utilizzato con qualcosa che viene eseguito in modo asincrono, forse chiamando il callback da un'altra discussione da qualche parte più avanti. Questa è una concorrenza "reale", a condizione che l'API che stai chiamando lo utilizza realmente in modo asincrono (ad esempio, utilizzo Future.async con le parti asincrone dell'SDK AWS come AmazonSimpleDBAsyncClient).

Se si vuole la concorrenza "reale" dal scalaz Task API direttamente è necessario utilizzare le cose come fork o gatherUnordered, come molti di default API verso l'essere sicuro/deterministico e riavviabile, con la concorrenza solo se esplicitamente richiesto.