Ok, alors commençons par l'exemple des secondes. Considérons l'extrait de code suivant:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object Test2{
def main(args:Array[String]):Unit={
val f = Future{Thread.sleep(5000); "i'm done"}
val r = for{
_ <- f
} yield "completed"
println(r)
}
}
Devinez ce qu'il imprimera? Il imprime
Future(<not completed>)
Process finished with exit code 0
Donc, en fait, ici, vous n'êtes pas en attente pour l'avenir de compléter, vous associez simplement le résultat du premier futur et le retourner comme l'autre futur qui complètera après la première est terminée. Comme vous le voyez, le programme n'attend pas que le futur qui en résulte soit terminé et quitte gracieusement. La compréhension for
sur les contrats à terme est une syntaxe de sucre pour la cartographie et les aplatir.
Les Await.result
et Await.ready
attendent vraiment que le futur se termine (ou expire pour passer). Mais ils le font de manière bloquante, donc votre fil où vous utilisez ces méthodes sera bloqué. Ce n'est pas toujours très mauvais et peut parfois être utile. Par exemple. dans de petits programmes de test ou une session REPL où vous voulez enfin sortir le résultat de vos futurs calculs sur la console, ou par exemple dans des tests où vous devez quand même attendre le résultat et tester n'a rien à faire en attendant. Une autre façon de vous voir aboutir à de tels petits programmes est d'utiliser scala.io.StdIn.readLine()
pour que le thread principal reste et ne sorte pas. Considérez ce qui suit qui illustre cela et vous fournit également une façon plus supplémentaire d'attendre l'achèvement futur:
object Test2{
def main(args:Array[String]):Unit={
val f = Future{Thread.sleep(5000); "i'm done"}
f foreach (println(_))
scala.io.StdIn.readLine()
}
}
Exécuter et vous verrez que le programme ne sort pas, affiche le résultat de l'avenir et sort ensuite seulement après avoir appuyé sur la touche ENTER.
foreach
appliqué à l'avenir est un raccourci pour ajouter l'écouteur onComplete
. Assez maniable.
En ce qui concerne la boucle while
vérifier en permanence si l'avenir est terminée - Je pense qu'il est probablement la pire façon d'attendre, car il gardera le fil conducteur occupé et déchets plus de puissance CPU au ralenti que de compter sur Await.result
efficacement mis en œuvre. Bloquer comme d'autres choses peut aussi bien être efficace et inefficace. Pour avoir une idée de tout cela avec des contrats à terme, vous devez réaliser clairement que l'exécution réelle du futur ne se fait pas dans le même fil que vous l'avez initié. Dans tous nos exemples, nous venons de définir le futur dans le thread principal, mais ensuite il a été exécuté dans l'un des threads dans les contextes d'exécution scala.concurrent.ExecutionContext.Implicits.global
importés.
Idéalement, vous éviterez l'attente (repousse-la aussi loin que possible) et la chaîne de contrats à terme (comme dans cette compréhension). – Thilo
si vous voulez interroger dans une boucle while, cela devrait être 'while (! IsCompleted)'. Mais mieux vaut utiliser 'Await.ready', qui a été fait dans ce but précis. – Thilo
Il y a deux réponses apparemment bonnes sous hwan, étaient-elles bonnes? – halfer