在scala中,如何声明嵌套类是瞬态的?

时间:2018-04-11 17:56:22

标签: scala apache-spark serialization

我有一个包含隐式转换的实用程序对象:

object Util {

  implicit class SparkView(sc: SparkContext) {

    def do(): Unit = sc.parallelize(1 to 10).foreach {
      doSomething()
    }
  }

  def doSomething(): Unit
}

开箱即用:

val sc = new SparkContext()
sc.do()

但是,当我将上面的Util实现更改为略有不同的内容时:

class Util {

  implicit class SparkView(sc: SparkContext) {

    def do(): Unit = sc.parallelize(1 to 10).foreach {
      doSomething()
    }
  }

  def doSomething(): Unit
}
case object Util extends Util

它的相同用法会产生以下错误:

> Task not serializable org.apache.spark.SparkException: Task not
> serializable  at
> org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:340)
>   at
> org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:330)
>   at
> org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:156)
>  ...
> Caused by: java.io.NotSerializableException:
> my.package.Util$SparkView
> Serialization stack:
>   - object not serializable (class: my.package.Util$SparkView, value:
> my.package.Util$SparkView@4f03729f)

事实证明,在第二种情况下,函数doSomething()被序列化并附带无用的东西(实际的函数签名变为this.$outer.doSomething())。立即修复将声明SparkView的所有实例都是瞬态的,这样它就不会被序列化和发送,并且可以从头开始从单例Util读取函数doSomething。我该如何轻松实现?

1 个答案:

答案 0 :(得分:1)

Spark ClosureCleaner不是序列化闭包的可靠工具。 Closure将this与所有字段一起捕获,然后ClosureCleaner尝试使用一些没有保证的启发式方法来取消未使用的字段。

因此,只需保持范围较小且代码简单,并希望它能够正常工作。

此外,您无法使SparkView成为瞬态,因为瞬态是字段的属性,而不是对象。