La façon dont vous présentez votre problème n'est vraiment pas dans le paradigme fonctionnel auquel scala est destiné. Ce que vous semblez vouloir, c'est faire une liste de calculs asynchrones, faire quelque chose à la fin de chacun, et autre chose quand tout est fini. C'est assez simple si vous utilisez des suites, qui sont simples à implémenter avec les méthodes map
et flatMap
sur Future
.
val fa: Future[Int] = Future { 1 }
// will apply the function to the result when it becomes available
val fb: Future[Int] = fa.map(a => a + 1)
// will start the asynchronous computation using the result when it will become available
val fc: Future[Int] = fa.flatMap(a => Future { a + 2 })
Une fois que vous avez tout cela, vous pouvez facilement faire quelque chose quand chacun de vos Future
finalise (avec succès):
val myFutures: List[Future[Int]] = ???
myFutures.map(futInt => futInt.map(int => int + 2))
Ici, je vais ajouter 2 à chaque valeur que je reçois de l'autre asynchrone calculs dans le List
.
Vous pouvez aussi choisir d'attendre que tous les Future
s dans votre liste complète en utilisant Future.sequence
:
val myFutureList: Future[List[Int]] = Future.sequence(myFutures)
Encore une fois, vous obtenez un Future
, qui sera résolu lorsque chacun des Future
s à l'intérieur la liste d'entrée est résolue avec succès, ou échouera chaque fois que l'un de vos Future
échouera. Vous pourrez alors utiliser map
ou flatMap
sur ce nouveau Future
, pour utiliser toutes les valeurs calculées en même temps.
Alors, voici comment j'écrire le code proposé:
val l = 1 to 10
val processings: Seq[Future[Unit]] = l.map {n =>
Future(println(s"processing $n")).map {_ =>
println(s"finished processing $n")
}
}
val processingOver: Future[Unit] =
Future.sequence(processings).map { (lu: Seq[Unit]) =>
println(s"Finished processing ${lu.size} elements")
}
Bien sûr, je recommande d'avoir des fonctions réelles plutôt que des procédures (retour Unit
), de sorte que vous pouvez avoir des valeurs à faire quelque chose avec. J'ai utilisé println
pour avoir un code qui produira le même résultat que le vôtre (à l'exception des tirages, qui ont une signification légèrement différente, puisque nous ne faisons plus de mutation).
Avez-vous besoin d'être mutable? Pourquoi avenir dans l'avenir? – mfirry
@mfirry J'ai besoin d'un moyen de faire quelque chose de différent quand la liste est vide (c'est-à-dire, quand tous les éléments ont été consommés et que les actions sont terminées). Ainsi, par exemple, vérifier que le dernier élément est en cours de traitement ne fonctionnerait pas, car il pourrait y avoir d'autres éléments en cours de traitement. La partie "Future inside Future" est d'imiter la structure du code réel - il a une raison d'être comme ça, je simplifie un peu ici. –
Ok. Mais avez-vous vraiment besoin de modifier le tampon? – mfirry