什么时候使用Scala期货?

时间:2019-09-19 16:31:40

标签: scala apache-spark apache-spark-sql future futuretask

我是Spark Scala程序员。我有一个火花工作,其中包含完成整个工作的子任务。我想使用Futures来并行完成子任务。完成全部工作后,我必须返回整个工作响应。

我听说scala期货是,一旦主线程执行并停止,其余线程将被杀死,并且您将得到空的响应。

我必须使用Await.result来收集结果。但是所有博客都告诉您应避免使用Await.result,这是一种不良做法。

在mycase中,是否使用Await.result是正确的方法??

def computeParallel(): Future[String] = {
  val f1 = Future {  "ss" }
  val f2 = Future { "sss" }
  val f3 = Future { "ssss" }

  for {
    r1 <- f1
    r2 <- f2
    r3 <- f3
  } yield (r1 + r2 + r3)
} 

computeParallel().map(result => ???)



根据我的理解,我们必须在Webservice类型的应用程序中使用Future,因为它始终运行着一个不会退出的进程。但就我而言,一旦逻辑执行(scala程序)完成,它将退出。

我可以使用期货解决我的问题吗?

预先感谢

1 个答案:

答案 0 :(得分:0)

除非特殊情况,否则不建议在Spark中使用Future,并且并行化计算也不是其中之一(很有可能使用非阻塞包装器来阻塞I / O(例如,向外部服务发出请求))唯一的特殊情况)。

请注意,Future不保证并行性(是否并行执行以及如何并行执行取决于运行它们的ExecutionContext),而是异步的。另外,如果您在Spark转换内生成计算性能良好的期货(即在执行程序上,而不是在驱动程序上),则由于Spark会在以下方面做得很好,因此性能可能不会有任何改善。保持执行者的核心忙碌,这些期货的全部产生都与Spark争夺核心。

广泛地,在结合并行抽象(例如Spark RDD / DStreams / Dataframe,actor和Future)时要非常小心:在许多潜在的雷区中,此类结合可能违反各个组件中的保证和/或约定。

还值得注意的是,Spark对中间值的可序列化性有要求,并且期货通常无法序列化,因此Spark阶段不会导致未来。这意味着您基本上别无选择,只能Await购买某个阶段产生的期货。

如果您仍然希望在Spark阶段生成期货(例如,将其发布到Web服务),则最好使用Future.sequence将期货折叠成一个,然后在该Await上折叠(请注意,我还没有检验过这个想法:我假设有一个隐式CanBuildFrom[Iterator[Future[String]], String, Future[String]]可用):

def postString(s: String): Future[Unit] = ???

def postStringRDD(rdd: RDD[String]): RDD[String] = {
  rdd.mapPartitions { strings =>
    // since this is only get used for combining the futures in the Await, it's probably OK to use the implicit global execution context here
    implicit val ectx = ???
    Await.result(strings.map(postString))
  }
  rdd  // Pass through the original RDD
}