Scala 在spark shell中使用全局对象时隐式val序列化

Scala 在spark shell中使用全局对象时隐式val序列化,scala,serialization,apache-spark,implicit,Scala,Serialization,Apache Spark,Implicit,我不清楚为什么(不可序列化)隐式val在这里被序列化(引发异常): 但当s1的值在闭合范围内时,则不是: implicit val sc2:SparkContext = sc sc.parallelize(Array(1,2,3)).map(x1 => "asdf".map(x => 4)) 我的用例显然更复杂,但我已经把它归结为这个问题 (解决方案是将隐式val定义为@transient)这取决于这些行所在的范围: 让我们看一下三个选项—在方法中,在没有s1的类中,以及在有s1的

我不清楚为什么(不可序列化)隐式val在这里被序列化(引发异常):

但当s1的值在闭合范围内时,则不是:

implicit val sc2:SparkContext = sc
sc.parallelize(Array(1,2,3)).map(x1 => "asdf".map(x => 4))
我的用例显然更复杂,但我已经把它归结为这个问题


(解决方案是将隐式val定义为@transient)

这取决于这些行所在的范围:

让我们看一下三个选项—在方法中,在没有
s1
的类中,以及在有
s1
的类中:

object TTT {

  val sc = new SparkContext("local", "test")

  def main(args: Array[String]): Unit = {
    new A().foo()  // works
    new B          // works
    new C          // fails
  }

  class A {
    def foo(): Unit = {
      // no problem here: vars in a method can be serialized on their own
      implicit val sc2: SparkContext = sc
      val s1 = "asdf"
      sc.parallelize(Array(1, 2, 3)).map(x1 => s1.map(x => 4)).count()
      println("in A - works!")
    }
  }

  class B {
    // no problem here: B isn't serialized at all because there are no references to its members
    implicit val sc2: SparkContext = sc
    sc.parallelize(Array(1, 2, 3)).map(x1 => "asdf".map(x => 4)).count()
    println("in B - works!")
  }

  class C extends Serializable {
    implicit val sc2: SparkContext = sc
    val s1 = "asdf" // to serialize s1, Spark will try serializing the YYY instance, which will serialize sc2
    sc.parallelize(Array(1, 2, 3)).map(x1 => s1.map(x => 4)).count() // fails
  }

}

底线-无论是否隐式,当且仅当
s1
sc2
是类的成员时,此操作将失败,这意味着该类必须序列化,并将同时“拖动”它们。

这取决于这些行所在的范围:

让我们看一下三个选项—在方法中,在没有
s1
的类中,以及在有
s1
的类中:

object TTT {

  val sc = new SparkContext("local", "test")

  def main(args: Array[String]): Unit = {
    new A().foo()  // works
    new B          // works
    new C          // fails
  }

  class A {
    def foo(): Unit = {
      // no problem here: vars in a method can be serialized on their own
      implicit val sc2: SparkContext = sc
      val s1 = "asdf"
      sc.parallelize(Array(1, 2, 3)).map(x1 => s1.map(x => 4)).count()
      println("in A - works!")
    }
  }

  class B {
    // no problem here: B isn't serialized at all because there are no references to its members
    implicit val sc2: SparkContext = sc
    sc.parallelize(Array(1, 2, 3)).map(x1 => "asdf".map(x => 4)).count()
    println("in B - works!")
  }

  class C extends Serializable {
    implicit val sc2: SparkContext = sc
    val s1 = "asdf" // to serialize s1, Spark will try serializing the YYY instance, which will serialize sc2
    sc.parallelize(Array(1, 2, 3)).map(x1 => s1.map(x => 4)).count() // fails
  }

}

底线-隐式或非隐式,当且仅当
s1
sc2
是类的成员时,此操作将失败,这意味着该类必须序列化,并将同时“拖动”它们。

作用域为spark shell REPL。在这种情况下,sc2(以及在顶级REPL作用域中定义的任何其他隐式val)只有在RDD操作中使用了该作用域中的隐式val和另一个val时才被序列化。这是因为隐式值需要全局可用,因此会自动序列化到所有工作节点

范围是spark shell REPL。在这种情况下,sc2(以及在顶级REPL作用域中定义的任何其他隐式val)只有在RDD操作中使用了该作用域中的隐式val和另一个val时才被序列化。这是因为隐式值需要全局可用,因此会自动序列化到所有工作节点

缺少更多的上下文:此代码驻留在何处-对象中?上课?功能?我认为这很重要,在某些情况下,
s1
在序列化时可能会带来它的“父”对象,这将导致
sc2
的序列化。范围会丢失更多的上下文:此代码驻留在哪里-在对象中?上课?功能?我认为这很重要,在某些情况下,
s1
在序列化时可能会带来它的“父”对象,这将导致
sc2
的序列化范围是spark shell REPL