2017-11-11 8 views
1

私が達成したいことが可能かどうかは確かです。私が知っていることは、エクゼキュータからシングルトンオブジェクトにアクセスして、コンストラクタが各エグゼキュータで一度だけ呼び出されていることを確認することです。このパターンはすでに実証済みで、私のコードベースで同様のユースケースに期待通りに機能します。エグゼキュータのSpark Object(シングルトン)シリアライズ

しかし、私が知りたいのは、オブジェクトをドライバで初期化した後に出荷できるかどうかです。このシナリオでは、 にアクセスすると、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

私が知りたいのは、オブジェクトがドライバで初期化された後に出荷できるかどうかです。

できません。 Objectsは、シングルトンとして実行されることはありません。最初にオブジェクトにアクセスするたびに、ローカルで初期化されます。

ExecutorAccessedObject(暗黙的にまたは明示的に)への引数として、またはExecutorAccessedObjectを変更可能にして(必要な同期を追加して)、呼び出しの結果をシリアル化できます。

+0

ありがとうございました。引数をオブジェクトに明示的に渡すと、argsを持つクラスになりますか? –

+0

私はむしろメソッド呼び出しのパラメタを考えていました。オブジェクトの代わりにクラスを使うこともうまくいくはずです。 – user8925690

関連する問題