2017-10-10 6 views
0

J'utilise Redis avec Scala. Redis tâche est un future donc je dois étudier le futur (Thread). J'ai trouvé tellement de façons d'attendre future pour arrêter. Je ne sais pas quelle est la différence. Quelle est la différence entre une compréhension Await, Thread.sleep et for?Dans Scala, quelle est la différence Await, Thread.sleep et pour les compréhensions?

val redisResult1 = redis.set(objectId, value) 
    Await.ready(redisResult1, Duration.Inf) 

    val redisResult2 = redis.set(objectId, value) 
    for { 
    _ <- redisResult2 
    } yield { 
    "end" 
    } 

    val redisResult3 = redis.set(objectId, value) 
    while(redisResult3.isCompleted) Thread.sleep(10) 
+0

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

+0

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

+0

Il y a deux réponses apparemment bonnes sous hwan, étaient-elles bonnes? – halfer

Répondre

1

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.

1

L'approche idiomatique consiste à ne pas bloquer pour le résultat. Au lieu de cela, vous devriez enchaîner Futures en utilisant map/pour les compréhensions et des choses comme ça. Un pour la compréhension est juste du sucre syntaxique pour flatMaps, maps et withFilters en fonction de la façon dont vous l'utilisez.

Non seulement cela n'est pas aussi bloquant que possible, mais il vous permet de coder le "chemin heureux" et de ne pas gérer les pannes le plus tard possible.

De nombreux frameworks comme Play vous permettent de ne jamais bloquer pour que l'avenir se termine et vous permet de renvoyer des Futures à l'appelant et le Framework le gère pour vous.

Si vous devez gérer déballant l'avenir, vous voulez certainement utiliser onComplete

Check out The Neophytes Guide to Scala pour un très bon tutoriel sur l'apprentissage ce genre de choses.