2017-11-11 179 views
1

我不確定我想實現的是否可能。我所知道的是,我正從一個執行器訪問單例對象,以確保它的構造器在每個執行器上只被調用一次。這種模式已經在我的代碼庫中被證明和按照預期用於類似的用例。執行者上的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 
} 

我試圖用廣播變量解決這個問題,但我不確定如何訪問單例對象內的廣播變量。

回答

2

我想知道的是,如果我可以在驅動程序初始化之後裝運對象。

你不能。作爲單身人士,我們絕不會將其運送給執行人。在本地初始化時,只要第一次訪問對象。

如果調用的結果是可序列化的,只需將其作爲參數傳遞給ExecutorAccessedObject(隱式或顯式地)或使ExecutorAccessedObject可變(並添加所需的同步)即可。

+0

謝謝你的回答。當你說明確地將參數傳遞給對象時,你的意思是使它成爲一個帶有參數的類? –

+0

我寧願考慮參數化方法調用。使用類而不是對象應該也可以。 – user8925690