2015-06-30 16 views
5

Ho una collezione di Promises. Stavo cercando un modo efficace per comporre lo Futures risultante. Attualmente il modo più pulito ho trovato di combinarli è stato quello di utilizzare uno scalaz Monoid, in questo modo:Come compongo un elenco di `Futures`?

val promises = List(Promise[Unit], Promise[Unit], Promise[Unit]) 

    promises.map(_.future).reduce(_ |+| _).onSuccess { 
    case a => println(a) 
    } 

    promises.foreach(_.success(())) 

C'è un modo pulito per fare questo che non richiede scalaz?

Il numero di Futures nella raccolta varierà e molte raccolte intermedie non sono desiderabili.

+0

Ti dispiacerebbe aggregare "Futures" anziché "Promesse"? –

+0

Questo è quello che sto facendo qui, estraggo il futuro con .map() –

risposta

7

Si potrebbe utilizzare Future.traverse:

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.{ Future, Promise } 

val promises = List(Promise[Unit], Promise[Unit], Promise[Unit]) 
Future.traverse(promises)(_.future) 

Questo vi darà una Future[List[Unit]], che non esattamente si qualifica come "un sacco di collezioni intermedi", ma non è necessariamente l'ideale, sia. Future.reduce funziona anche:

Future.reduce(promises.map(_.future))((_, _) =>()) 

Questo restituisce una Future[Unit] che sarà soddisfatta quando tutti i future sono soddisfatti.

+0

Dato che costruisce una collezione, mi chiedo se il monoide sia più efficiente. Ma grazie, questo è esattamente quello che stavo cercando - apparentemente non so come usare i documenti API come non ho mai fatto clic sulla versione Object di Future. –

+0

'reduce' non crea una raccolta, quindi dovrebbe essere almeno efficiente quanto il monoide (probabilmente di più). –

+0

Sì, sto usando riduci nel mio esempio sopra, più veloce o meno dipenderebbe da cosa hai sostituito '| + |'. La traversa crea una lista, quindi penso che possa introdurre qualche piccolo sovraccarico. Ho solo una manciata di futuri, quindi la lista è breve e probabilmente non importa. –

3

Future.sequence è il metodo che si desidera.

+0

'Future.traverse' probabilmente ha un po 'più senso (vedi la mia risposta), ma crea comunque almeno una raccolta intermedia non necessaria. –

+0

La sequenza semplifica la traversata, quindi hai entrambi ragione ma potrei accettarne solo uno. Scusate. –

+0

In questo caso, 'traverse' è in realtà più semplice ed efficiente: combina la' map' necessaria e la 'sequenza' in un'unica operazione. –