我是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程序)完成,它将退出。
我可以使用期货解决我的问题吗?
预先感谢
答案 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
}