在Spark的map
或flatMap
内创建中间变量会导致性能降低吗?
这是一些应该做相同事情的代码的两个版本。
v1:
val x = someRDD.flatMap { case(id, row) =>
if (row.flag.isDefined)
Some((id, (Some(row.a.get), Some(row.b.get),
if (someFunction(row.c.get) 1 else 0, 1)))
else
Some((id, (Some(row.a.get), None,
if (someFunction(row.c.get) 1 else 0, 1)))
}
v2:
val x = someRdd.flatMap { case(id, row) =>
val a = Some(row.a.get)
val b = if (row.flag.isDefined) Some(row.b.get) else None
val c = if (someFunction(row.c.get) 1 else 0
Some((id, (a, b, c, 1)))
}
区别在于v1避免像v2一样创建任何中间变量。
与v1相比,v2的性能是否较差? a, b, c
val的创建是否需要稍后的垃圾回收步骤(例如:由于清理needed on the root objects),这会使它慢得多?
很明显,这是依赖于数据的,详细的分析对于确定性地回答这个问题是必要的,但是我想知道,通常来说,使用中间变量是否会导致性能下降。
我认为从代码可读性的角度来看,v2更好,但是如果我们遵循v1,会过早优化吗?
答案 0 :(得分:3)
原始值(例如您的c
变量)可能根本没有区别。编译器足够聪明,可以对其进行优化。对于引用类型,正式创建值的确会导致收集更多垃圾,因此从理论上讲,这可能会影响性能。但是,实际上,您很可能不会注意到性能上的差异(除非您确实创建了很多临时对象,例如成千上万个大型数组)-有些JIT优化可能从这里开始,并且垃圾收集在当今尤其有效,尤其是在处理大量短期对象时。
最好的答案是描述您的工作,不要尝试提前改善类似的情况。在其他所有事情都停止提供帮助之后,我个人会把这样的优化视为最后一步。在大多数情况下,您可以通过优化工作计划来获得令人印象深刻的性能提升,例如通过删除不必要的混洗或确保分区的大小均匀。