我想计算我的Spark程序执行速度,但由于懒惰,这很困难。我们在这里考虑这个(无意义的)代码:
var graph = GraphLoader.edgeListFile(context, args(0))
val graph_degs = graph.outerJoinVertices(graph.degrees).triplets.cache
/* I'd need to start the timer here */
val t1 = System.currentTimeMillis
val edges = graph_degs.flatMap(trip => { /* do something*/ })
.union(graph_degs)
val count = edges.count
val t2 = System.currentTimeMillis
/* I'd need to stop the timer here */
println("It took " + t2-t1 + " to count " + count)
问题是,转换是懒惰的,因此在val count = edges.count
行之前不会对任何内容进行评估。但根据我的观点t1
得到一个值,尽管上面的代码没有值......上面的代码t1
在计时器启动后得到评估,尽管代码中的位置。那是一个问题...
在Spark Web UI中,我找不到任何有趣的内容,因为我需要在特定代码行之后花费的时间。您是否认为有一个简单的解决方案可以确定何时对一组转换进行真实评估?
答案 0 :(得分:3)
由于连续转换(在同一任务中 - 意味着,它们不会被 shuffles 分隔并作为同一动作的一部分执行)作为单个"步骤"执行,Spark 不单独测量它们。从驱动程序代码 - 你也可以。
可以做的是衡量将 功能应用于每条记录的持续时间,并使用累加器对其进行总结,例如:
// create accumulator
val durationAccumulator = sc.longAccumulator("flatMapDuration")
// "wrap" your "doSomething" operation with time measurement, and add to accumulator
val edges = rdd.flatMap(trip => {
val t1 = System.currentTimeMillis
val result = doSomething(trip)
val t2 = System.currentTimeMillis
durationAccumulator.add(t2 - t1)
result
})
// perform the action that would trigger evaluation
val count = edges.count
// now you can read the accumulated value
println("It took " + durationAccumulator.value + " to flatMap " + count)
您可以对任何单个转换重复此操作。
<强>免责声明强>:
样式注释:
您可以通过创建一个&#34;包装&#34;的measure
函数来使此代码更具可重用性。围绕任何函数并更新给定的累加器:
// write this once:
def measure[T, R](action: T => R, acc: LongAccumulator): T => R = input => {
val t1 = System.currentTimeMillis
val result = action(input)
val t2 = System.currentTimeMillis
acc.add(t2 - t1)
result
}
// use it with any transformation:
rdd.flatMap(measure(doSomething, durationAccumulator))
答案 1 :(得分:0)
Spark Web UI记录每一个动作,甚至报告该动作的每个阶段的时间 - 它都在那里!您需要查看阶段选项卡,而不是工作。我发现只有编译并提交代码才能使用它。它在REPL中没用,你有机会使用它吗?