我理解通常在访问字段或超出闭包范围的方法时出现的“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表示嵌套函数的方式有关吗?
处理此问题的推荐方法是什么? 避免使用嵌套函数?
答案 0 :(得分:1)
是不是会妨碍第一种情况f.map(mapFN(_))
相当于f.map(new Function() { override def apply(...) = mapFN(...) })
,而第二种情况只是f.map(mapFN)
?当您使用def
声明方法时,它可能只是某个匿名类中的一个方法,对隐藏类的隐式$outer
引用。但map
需要Function
,因此编译器需要包装它。在包装器中,您只需引用该匿名类的某些方法,但不引用该实例本身。如果您使用val
,则可以直接引用传递给map
的函数。我不确定这个,只是大声思考......