【问题标题】:Does method parameter trigger serialization in Spark?Spark中的方法参数是否触发序列化?
【发布时间】:2019-05-21 17:38:33
【问题描述】:

我阅读了关于传递函数的Spark programming guide,想知道当函数引用外部方法参数/局部变量时会发生什么。

例如,我有这个对象

object Main {
  def main(args: Array[String]): Unit = {
    val ds: Dataset[String] = ???
    ds.map(_ + args(0))
  }
}

Spark 是否必须序列化 Main?如果argsmain 中的局部变量怎么办?

【问题讨论】:

    标签: scala apache-spark serialization


    【解决方案1】:

    不,在这两种情况下,Spark 都不会序列化 Main 对象。方法参数和局部变量(从语义角度来看几乎是同一件事)不“属于”封闭对象或类,它们与特定的方法调用相关联,因此可以直接被闭包捕获。

    作为一般规则,如果您需要引用某个对象才能访问某个值,那么该引用将被捕获并因此被序列化:

    class Application(n: Int) {
      val x = "internal state " + n
    
      def doSomething(ds: Dataset[String], param: String): Unit = {
        ds.map(_ + x + param)
      }
    }
    

    注意这里为了访问x,它是一个instance成员,你必须有封闭的实例可用,因为它取决于实例的实际参数构造与。另一种看待它的方式是记住,当你在上面的例子中使用x时,它实际上是this.x的快捷方式:

    ds.map(_ + this.x + param)
    

    与此相比,param 值没有这种依赖关系——它按原样传递给方法,无需访问任何其他封闭对象即可使用它。所以param会被直接捕获并序列化。

    这就是为什么建议将实例成员放入局部变量以免捕获整个对象:当您将值放入局部变量时,它不再需要访问封闭的实例:

    val localX = this.x
    ds.map(_ + localX + param)
    

    当然,如果你有对封闭实例的引用你想要捕获的对象,像这里:

    class Inner(app: Application)
    
    class Application {
      val x = new Inner(this)
    
      def doSomething(ds: Dataset[String]): Unit = {
        val localX = x
        ds.map(_ + localX.toString)
      }
    }
    

    然后将其存储到局部变量将无济于事,因为 Spark 仍需要序列化 ​​Inner 类的 app 字段,该字段指向 Application 实例。这就是为什么如果您在 Spark 方法中使用的复杂对象图将被发送到执行程序时,您必须小心。

    【讨论】:

    • 哇,感谢您提供如此详细的答案。如果我可以投票两次,我会的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-23
    • 2015-07-30
    • 2015-10-28
    • 2021-10-22
    相关资源
    最近更新 更多