【问题标题】:Flaky onSuccess of Future.sequenceFlaky onSuccess of Future.sequence
【发布时间】:2015-03-20 14:39:36
【问题描述】:

我写了这个方法:

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

object FuturesSequence extends App {
  val f1 = future {
    1
  }

  val f2 = future {
    2
  }

  val lf = List(f1, f2)

  val seq = Future.sequence(lf)

  seq.onSuccess {
    case l => println(l)
  }
}

我期待 Future.sequence 将 List[Future] 收集到 Future[List] 中,然后等待每个期货(在我的情况下为 f1 和 f2)完成,然后在我的 Future[List] seq 上调用 onSuccess案例。

但在多次运行此代码后,它只会偶尔打印一次“List(1, 2)”,我无法弄清楚为什么它不能按预期工作。

【问题讨论】:

  • 应用程序在回调执行前退出。
  • 正如其他人所说。默认执行上下文在不会阻止 JVM 退出的守护线程上运行您的期货。如果这是为了快速测试,最简单的方法是在 seq 上使用 Await.result
  • 那么改变执行上下文是唯一的方法吗?或者他们是另一种具有正确行为和当前执行上下文的方法(可能是异步阶段结束时的阻塞步骤,当我等待所有结果返回时不是那么糟糕吗?)

标签: scala sequence future intermittent


【解决方案1】:

试试这个,

import scala.concurrent._
import java.util.concurrent.Executors
import scala.util.{ Success, Failure }

object FuturesSequence extends App {
  implicit val exec = ExecutionContext.fromExecutor(Executors.newCachedThreadPool)
  val f1 = future {
    1
  }

  val f2 = future {
    2
  }

  val lf = List(f1, f2)

  val seq = Future.sequence(lf)

  seq.onSuccess {
    case l => println(l)
  }
}

这将始终打印List(1,2)。原因很简单,上面的exec 是线程(不是守护线程)的 ExecutionContext,而在您的示例中,ExecutionContext 是默认的从包含守护线程的ExecutionContext.Implicits.global 隐式获取的。

因此作为守护进程,该进程不会等待 seq 未来完成并终止。如果seq 确实完成了,那么它就会打印出来。但这并不总是发生

【讨论】:

  • 这样写期货时,期货是否会超时?问是因为我更喜欢未来而不是线程,以防我想要返回类型
  • 期货本身不会超时。除非您明确尝试取消它。即使在这种情况下,也只是可能设置的线程的中断状态,仅此而已。
【解决方案2】:

应用程序在未来完成之前退出。

You need to block until the future has completed。这可以通过多种方式实现,包括更改 ExecutionContext、实例化新的 ThreadPool、Thread.sleep 等,或者使用 scala.concurrent.Await 上的方法

编写代码最简单的方法是使用Await.ready。这会阻塞future 一段指定的时间。在下面修改后的代码中,应用程序在退出前等待了 5 秒。

还要注意,额外的导入scala.concurrent.duration,所以我们可以指定等待的时间。

import scala.concurrent._
import scala.concurrent.duration._
import java.util.concurrent.Executors
import scala.util.{ Success, Failure }

object FuturesSequence extends App {
  val f1 = future {
    1
  }

  val f2 = future {
    2
  }

  val lf = List(f1, f2)

  val seq = Future.sequence(lf)

  seq.onSuccess {
    case l => println(l)
  }

  Await.ready(seq, 5 seconds)
}

改用Await.result,您也可以跳过onSuccess 方法,因为它会将结果列表返回给您。

例子:

val seq: List[Int] = Await.result(Future.sequence(lf), 5 seconds)
println(seq)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-21
    • 2018-08-13
    • 1970-01-01
    • 2021-07-18
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多