我试图使用像这样的代码(在Scala中)在RDD上记录每个mapPartition操作的执行时间:
rdd.mapPartitions{partition =>
val startTime = Calendar.getInstance().getTimeInMillis
result = partition.map{element =>
[...]
}
val endTime = Calendar.getInstance().getTimeInMillis
logger.info("Partition time "+(startTime-endTime)+ "ms")
result
}
问题是它在开始执行地图操作之前立即记录“分区时间”,因此我总是获得2 ms的时间。
我通过观察Spark Web UI注意到它,在日志文件中,关于执行时间的行在任务开始后立即出现,而不是按预期结束。
有人能够解释我为什么吗?在mapPartitions中,代码应该线性执行,否则我错了?
由于
此致 卢卡
答案 0 :(得分:3)
partitions
内的{p> mapPartitions
是Iterator[Row]
,并且在Scala中懒惰地评估Iterator
(即,当使用迭代器时)。这与Spark的懒惰唤醒无关!
调用partitions.size
将触发对映射的评估,但会使用Iterator(因为它只能迭代一次)。一个例子
val it = Iterator(1,2,3)
it.size // 3
it.isEmpty // true
您可以做的是将Iterator转换为非惰性集合类型:
rdd.mapPartitions{partition =>
val startTime = Calendar.getInstance().getTimeInMillis
result = partition.map{element =>
[...]
}.toVector // now the statements are evaluated
val endTime = Calendar.getInstance().getTimeInMillis
logger.info("Partition time "+(startTime-endTime)+ "ms")
result.toIterator
}
编辑:请注意,您可以使用System.currentTimeMillis()
(甚至是System.nanoTime()
)而不是Calendar
。