Нет, в обоих этих случаях Spark не сериализует объект Main
.Аргументы метода и локальные переменные (которые с точки зрения семантики в значительной степени совпадают) не «принадлежат» окружающему объекту или классу, они связаны с конкретным вызовом метода и поэтому могут быть непосредственно захвачены замыканием.
Как правило, если вам нужна ссылка на некоторый объект для доступа к какому-либо значению, эта ссылка будет захвачена и, следовательно, сериализована:
class Application(n: Int) {
val x = "internal state " + n
def doSomething(ds: Dataset[String], param: String): Unit = {
ds.map(_ + x + param)
}
}
Обратите внимание, что здесьдля доступа к x
, который является экземпляром члена, вам обязательно нужно иметь включающий экземпляр, чтобы он был доступен, потому что это зависит от фактических параметров, с которыми был создан экземпляр.Другой способ увидеть это - помнить, что когда вы используете 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 все равно нужно было бы сериализовать поле app
класса Inner
, которое указывает на экземпляр Application
.Вот почему вы должны быть осторожны, если у вас есть сложные графы объектов, которые вы используете в методах Spark, которые будут отправлены исполнителям.