执行者上的Spark对象(单例)序列化
问题描述:
我不确定我想实现的是否可能。我所知道的是,我正从一个执行器访问单例对象,以确保它的构造器在每个执行器上只被调用一次。这种模式已经在我的代码库中被证明和按照预期用于类似的用例。执行者上的Spark对象(单例)序列化
但是,我想知道的是,如果我可以在驱动程序初始化之后运送对象。在这种情况下, 访问ExecutorAccessedObject.y
时,理想情况下它不会调用println,而是返回值。这是一个高度简化的版本,实际上,我想打电话给驱动程序上的某个外部系统,因此在执行程序*问时,它不会重新调用该外部系统。我确信@transient lazy val x
在执行者上被重新初始化,因为这将持有无法序列化的连接池。
object ExecutorAccessedObject extends Serializable {
@transient lazy val x: Int = {
println("Ok with initialzing this on the executor. I.E. database connection pool")
1
}
val y: Int = {
// call some external system to return a value.
// I do not want to call the external system from the executor
println(
"""
|Idealy, this would not be printed on the executor.
|return value 1 without re initializing
""")
1
}
println("The constructor will be initialized Once on each executor")
}
someRdd.mapPartitions { part =>
ExecutorAccessedObject
ExecutorAccessedObject.x // first time accessed should re-evaluate
ExecutorAccessedObject.y // idealy, never re-evaluate and return 1
part
}
我试图用广播变量解决这个问题,但我不确定如何访问单例对象内的广播变量。
答
我想知道的是,如果我可以在驱动程序初始化之后装运对象。
你不能。作为单身人士,我们绝不会将其运送给执行人。在本地初始化时,只要第一次访问对象。
如果调用的结果是可序列化的,只需将其作为参数传递给ExecutorAccessedObject
(隐式或显式地)或使ExecutorAccessedObject
可变(并添加所需的同步)即可。
谢谢你的回答。当你说明确地将参数传递给对象时,你的意思是使它成为一个带有参数的类? –
我宁愿考虑参数化方法调用。使用类而不是对象应该也可以。 – user8925690