【问题标题】:Value of future depends on whether it has been bound to a variable?未来的价值取决于它是否已经绑定到一个变量?
【发布时间】:2016-12-22 23:34:19
【问题描述】:

代码:

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)
}

注意两者之间的区别:

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

即,在将未来的值分配给变量后检索它会给我一个Some(Success(43)),而直接检索它会给出None。为什么?

还要注意onComplete 方法会产生预期的行为,尽管它是在println(fut.map(_ + 1).value) 行之后调用的。

Scala 2.12.0

【问题讨论】:

    标签: scala future


    【解决方案1】:

    fut.map(_ + 1) 返回一个新的Future,其.value 可能尚未完成。如果没有,那么你会得到println 显示的None,否则你会得到Some(Success(43))

    你可以在 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
    

    编辑
    显示代码的非确定性结果(不做任何更改):

    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))
    

    【讨论】:

    • 睡眠主线程似乎对我的机器没有帮助。您能否在 Scala 中确认这一点 App
    • @qed:我不确定你的意思。 Thread.sleep 没有分配 .map 结果不会影响任何事情,并且分配它有点与问题相矛盾。
    • @qed:我添加了 4 次代码运行的输出以表明它并不总是相同。
    • 啊,我明白了。 fut.map(_ + 1).value 立即检索该值,而无需等待未来完成。在这里休眠主线程确实应该没有影响。
    【解决方案2】:

    我认为您刚刚遇到了时间问题,因为您没有正确等待期货完成。在 Scala REPL 中运行最后一次计算时,它实际上有时会打印 None,有时会打印 Some(Success(43))

    但是,如果,例如,您跑了:

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

    它总是会打印 43。你需要确保你的程序在未来完成之前不会终止,当然才能看到结果。

    【讨论】:

    • 在我的机器上,即使线程休眠 5 秒也无济于事。
    • 顺便说一下应该是onCompleteonSuccess 已弃用。
    • 你的Thread.sleep 5s 在哪里,你在我粘贴代码之后,即在程序结束时尝试过吗?是的,看起来你是对的; onSuccess 在 Scala 2.12 中已弃用。
    • 好的。这对我有用,根据您编辑的问题,它看起来也对您有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多