我需要对DataFrame进行不同的过滤操作并计数,然后对各个计数求和。我使用Scala Future进行并发执行。这是代码:
import scala.concurrent.{Await, Future, blocking}
import scala.concurrent.ExecutionContext.Implicits.global
val f1 = Future{myDF.filter("pmod(idx, 8) = 1").count}
val f2 = Future{myDF.filter("pmod(idx, 8) = 2").count}
val f3 = Future{myDF.filter("pmod(idx, 8) = 3").count}
val future = for {c1 <- f1; c2 <- f2; c3 <- f3} yield {
c1 + c2 + c3
}
val summ = Await.result(future, 180 second)
每次过滤/计数操作的运行时间大约需要7秒。但是,在多次运行之后,并发执行的总时间总是大约需要35秒,而不是我预期的7秒。很长一段时间以来,我一直对这种行为感到困惑,但无法理解。
我有一个由3台机器组成的集群,一个主节点,两个工作节点,每个节点有128G内存和32个内核。数据大小约为3G。我注意到在并发执行期间,一个工作节点有20秒的GC时间。我调整了GC,使得单独的过滤/计数操作几乎没有GC时间。我不确定为什么每当我运行3个Futures的并发执行时GC都会启动,以及它是否是导致并发执行时间更长的原因。
任何人都有这方面的经验吗?
答案 0 :(得分:1)
以顺序方式在您的cluser中调度作业,因为脚本中的每个作业都是作业DAG中的一个节点,用于定义它们操作的数据之间的优先关系。并且,对整个脚本的任何成功执行都必须尊重该优先级。
即使您的工作之间没有前因关系,这条规则也适用(尽管它们都依赖于相同的数据,myDF)。而您对Futures的使用仅意味着您的作业几乎同时提交到调度程序,而不是最终以这种方式安排。
如果你想要并行性,你应该在一份工作中写下它,比如:
myDF.filter("pmod(idx,8) < 4 && pmod(idx,8) > 0").groupBy("pmod(idx,8)").count()
是的,你应该缓存myDf