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
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.
Si può anche leggere il meraviglioso Timothy Perrett blog post su Scalaz Task and Future che copre molti dettagli non così ovvi.
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.
Quando si compone Attività con mappa e flatMap si può ottenere una vittoria prestazioni non usando forchetta, vedi:
http://blog.higher-order.com/blog/2015/06/18/easy-performance-wins-with-scalaz/
Questa risposta potrebbe essere migliorata facendo riferimento al blog, ma tra cui le informazioni pertinenti qui. Non c'è modo di fare affidamento su un blog esistente in futuro. – axlj