private def show(now: Long, stages: Seq[SparkStageInfo]) {
val width = TerminalWidth / stages.size
val bar = stages.map { s =>
val total = s.numTasks()
val header = s"[Stage ${s.stageId()}:"
val tailer = s"(${s.numCompletedTasks()} + ${s.numActiveTasks()}) / $total]"
val w = width - header.length - tailer.length
val bar = if (w > 0) {
val percent = w * s.numCompletedTasks() / total
(0 until w).map { i =>
if (i < percent) "=" else if (i == percent) ">" else " "
}.mkString("")
} else {
""
}
header + bar + tailer
}.mkString("")
// only refresh if it's changed of after 1 minute (or the ssh connection will be closed
// after idle some time)
if (bar != lastProgressBar || now - lastUpdateTime > 60 * 1000L) {
System.err.print(CR + bar)
lastUpdateTime = now
}
lastProgressBar = bar
}
下面是在高层次上发生的事情: Spark 将工作分阶段进行,并在每个阶段中完成任务。这个进度指示器意味着阶段 X 由 C 任务组成。在执行过程中,A 和 B 从零开始并不断变化。A 始终是已经完成的任务数,B 是当前正在执行的任务数。对于一个有很多任务的阶段(比你拥有的工人多得多) ,你应该期望看到 B 增长到一个与集群中有多少工人相对应的数字,然后你应该开始看到 A 随着任务的完成而增加。接近尾声的时候,当最后几个任务执行时,B 将开始减少,直到它达到0,这时 A 应该等于 C,阶段结束,火花移动到下一个阶段。C 将在整个过程中保持不变,记住它是阶段中任务的总数,并且永远不变。