【问题标题】:Using intermediate variables inside a Spark map在 Spark 映射中使用中间变量
【发布时间】:2019-02-25 20:36:02
【问题描述】:

在 Spark 中的 mapflatMap 中创建中间变量会导致性能下降吗?

这里有两个版本的一些代码应该做同样的事情。

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 vals 的创建是否需要稍后的垃圾收集步骤(例如:由于清理 needed on the root objects),这会使其速度变慢?

显然,这是依赖于数据的,详细的分析对于明确回答这个问题是必要的,但我想知道,一般来说,使用中间变量是否会导致性能下降。

我觉得从代码可读性方面来说,v2 更好,但如果我们推迟到 v1 会不会是过早的优化?

【问题讨论】:

    标签: scala apache-spark garbage-collection


    【解决方案1】:

    对于原始值(例如您的 c 变量),可能根本没有区别。编译器足够聪明,可以优化它。对于引用类型,正式创建值确实会导致收集更多垃圾,所以理论上是的,这可能会影响性能。然而,在实践中,您很可能不会注意到性能差异(除非您确实创建了 很多 临时对象,例如成百上千的大型数组) - 有 JIT 优化可能从这里开始,现在垃圾收集也非常有效,尤其是在处理大量短期对象时。

    最好的答案是描述你的工作,不要提前尝试改进这样的事情。在其他一切都停止提供帮助之后,我个人会将这样的优化视为最后一步。在大多数情况下,您可以通过优化工作计划来实现更令人印象深刻的性能改进,例如通过删除不必要的洗牌或确保您的分区大小均匀。

    【讨论】:

      猜你喜欢
      • 2016-11-18
      • 1970-01-01
      • 2020-12-27
      • 2020-06-13
      • 2022-01-22
      • 1970-01-01
      • 2019-09-24
      • 1970-01-01
      • 2017-09-25
      相关资源
      最近更新 更多