2016-12-22 1 views
3

code:La valeur du futur dépend de si elle a été liée à une variable?

import scala.concurrent.Future 
import scala.util.{Failure, Success} 
import scala.concurrent.ExecutionContext.Implicits.global 

/** 
    * Created by IDEA on 12/23/16. 
    */ 
object Demo extends App { 
    val fut = Future { 
    Thread.sleep(100) 
    21 + 21 
    } 
    val f = Future { 5 } 
    Thread.sleep(200) 
    val fut1 = fut.map(_ + 1) 
    println(fut1) // Future(Success(43)) 
    println(fut1.value) // Some(Success(43)) 
    println(fut.map(_ + 1).value) // None 
    fut.map(_ + 1).onComplete { 
    case Success(v) => println(v) 
    case Failure(e) => println(e) 
    } // 43 

    (for { 
    x <- Future {Thread.sleep(100); 21 + 21} 
    y <- Future {Thread.sleep(100); 21 + 22} 
    } yield x + y).andThen { 
    case Success(v) => println(v) 
    } 
    Thread.sleep(5000) 
} 

Notez la différence entre:

println(fut1.value) // Some(Success(43)) 
println(fut.map(_ + 1).value) // None 

à savoir, la récupération de la valeur de l'avenir après l'attribution à une variable me donne un Some(Success(43)), lors de la récupération donne directement None. Pourquoi?

Notez également que la méthode onComplete génère le comportement attendu, bien qu'elle ait été appelée après la ligne println(fut.map(_ + 1).value).

Scala 2.12.0

Répondre

7

fut.map(_ + 1) retourne une nouvelle Future, dont .value peut ne pas avoir été encore terminé. Si ce n'est pas le cas, alors vous obtenez le None les spectacles println, sinon vous obtiendrez Some(Success(43)).

Vous pouvez le voir dans le REPL:

// Paste the body of your Demo object before 
// Then repeatedly call the last println: 

scala> println(fut.map(_ + 1).value) // None 
Some(Success(43)) 

scala> println(fut.map(_ + 1).value) // None 
None 

scala> println(fut.map(_ + 1).value) // None 
Some(Success(43)) 

scala> println(fut.map(_ + 1).value) // None 
Some(Success(43)) 

scala> println(fut.map(_ + 1).value) // None 
None 

Modifier:
Affichage des résultats non-déterministe de votre code (sans modifier celui-ci):

scala> Demo.main(Array()) 
List() 
None 
Some(Success(43)) 

scala> Demo.main(Array()) 
List() 
None 
None 

scala> Demo.main(Array()) 
List() 
None 
None 

scala> Demo.main(Array()) 
Success(43) 
Some(Success(43)) 
Some(Success(43)) 
+0

Dormir le fil principal ne semble pas du tout aider sur ma machine. Pourriez-vous confirmer cela dans une scala 'App'? – qed

+0

@qed: Je ne suis pas sûr de ce que vous voulez dire. Un 'Thread.sleep' sans assigner le résultat de' .map' n'affectera rien, et l'assigner en quelque sorte contredit la question. – Marth

+0

S'il vous plaît voir ma modification. – qed

2

I pense que vous avez juste frappé un problème de synchronisation parce que vous n'attendez pas correctement que les contrats à terme se terminent. Lors de l'exécution du dernier calcul dans la Scala REPL, il donne parfois parfois des tirages None, parfois Some(Success(43)).

Si toutefois, par ex. a couru:

fut.map(_ + 1).onComplete { 
    case Success(v) => println(v) 
    case Failure(ex) => 
} 
Thread.sleep(100) 

Il serait toujours imprimer 43. Vous devez vous assurer que votre programme ne se termine pas avant l'avenir est complet bien sûr de voir le résultat.

+0

Sur ma machine, même dormir le fil pendant 5 secondes n'aide pas. – qed

+0

Doit être 'onComplete' d'ailleurs. 'onSuccess' est obsolète. – qed

+0

Où était votre Thread.sleep pendant 5s, l'avez-vous essayé après le code que j'ai collé, c'est-à-dire à la fin du programme? Ouais, on dirait que tu as raison; 'onSuccess' est obsolète dans Scala 2.12. – m01