避免"任务不可序列化"使用类中的嵌套方法

时间:2014-05-19 08:26:09

标签: apache-spark

我理解通常在访问字段或超出闭包范围的方法时出现的“Task not serializable”问题。

要修复它,我通常会定义这些字段/方法的本地副本,这样就不需要序列化整个类:

class MyClass(val myField: Any) { 
  def run() = { 
    val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv") 

    val myField = this.myField 
    println(f.map( _ + myField ).count) 
  } 
} 

现在,如果我在run方法中定义嵌套函数,则无法序列化:

class MyClass() { 
  def run() = { 
    val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv") 

    def mapFn(line: String) = line.split(";") 

    val myField = this.myField 
    println(f.map( mapFn( _ ) ).count) 

  } 
} 

我不明白因为我认为“mapFn”会在范围内...... 更奇怪的是,如果我将mapFn定义为val而不是def,那么它可以工作:

class MyClass() { 
  def run() = { 
    val f = sc.textFile("hdfs://xxx.xxx.xxx.xxx/file.csv") 

    val mapFn = (line: String) => line.split(";") 

    println(f.map( mapFn( _ ) ).count)     
  } 
} 

这与Scala表示嵌套函数的方式有关吗?

处理此问题的推荐方法是什么? 避免使用嵌套函数?

1 个答案:

答案 0 :(得分:1)

是不是会妨碍第一种情况f.map(mapFN(_))相当于f.map(new Function() { override def apply(...) = mapFN(...) }),而第二种情况只是f.map(mapFN)?当您使用def声明方法时,它可能只是某个匿名类中的一个方法,对隐藏类的隐式$outer引用。但map需要Function,因此编译器需要包装它。在包装器中,您只需引用该匿名类的某些方法,但不引用该实例本身。如果您使用val,则可以直接引用传递给map的函数。我不确定这个,只是大声思考......