2016-07-13 18 views
0

ある間隔でデータベースをポーリングしたいと思います。サーバの負荷を避けるために、重複する実行を回避することが主な関心事です。と、時間軸上で均等に間隔を空けて実行することはありません。;これはナイーブタイマー方式では他に発生します。実行間隔を固定したスカラスケジューリング

違う言い方:実行の終わりと次の開始時刻との間隔を一定にしたいと思います。

俳優たちが持っているコードの定型句のせいで、私はこれを試してみました。たぶん、より良い、あるいはもっと簡単な方法があります。

/* 
    * Infinite scheduling for acquiring a database snapshot at an almost fixed interval. 
    * The actual effective acquisition interval is (duration of the acquisition + dbSyncIntervalSecs) 
    */ 

    import scala.concurrent.duration._ 
    import scala.concurrent.blocking 
    import scala.concurrent.Future 
    import scala.concurrent.ExecutionContext.Implicits.global 

    val system = ActorSystem("MySystem") // make global if more things hinge on the actor system 

    val interval = Configuration.dbSyncIntervalSecs 

    private def acquireLoop: Unit = { 
    Future { 
     blocking { 
     println("about to sync from database") 
     acquire 
     } 
    } 
    system.scheduler.scheduleOnce(interval seconds)(acquireLoop) 
    } 

アドバイスはありますか?

スレッドプールは、しかし、健康になります。

enter image description here

また、私はより良い、この継続的なプロセスのために、特定の種類の個別の実行コンテキストを使用するのではなく、blockingイディオムでデフォルト1を背負う必要がありますか?

ありがとうございます!

答えて

2

「通常の」schedule methodは、あなたが望むことを保証します - 提出された=> Unitブロックは一度に1つの方法でのみ実行されます。

スケジュール初期遅延と 頻度で繰り返し実行される機能:ドキュメントから引用

。例えば。関数を2 秒後に実行し、その後100msごとに実行する場合は、delay = Duration(2、 TimeUnit.SECONDS)とinterval = Duration(100、TimeUnit.MILLISECONDS)を設定します。 関数の実行に間隔よりも時間がかかる場合、 が完了した直後に の実行が開始されます。(関数の重複はありません)

(EMPH鉱山)

EDIT:あなたは今、あなたが一定時間同様実行の間にしたい言及しました。

与えられた初期遅延、後の最初の を有効にし、その後、終端間の一定の遅延 となった定期的なアクションを作成し、実行:まあ、都合の代替は、単にJavaのAPIのScheduledExecutorService#scheduleWithFixedDelayを使用するです1回の実行と、 の開始を示します。

(EMPH鉱山)

は残念ながら、この方法には直接相当するものはありません - Scalaのライブラリで、またアッカScheduler APIでもありません。使用法では、あなたの仕事をRunnableとして定義する必要がありますが、それは問題ではありません。

(個人的に、私はscheduleOnceでシンプルな俳優を使うだろうが、あなたがそれらを避けたい言及した)

+0

お役立ち情報私はまだ遅いものが終了した直後にタイマーに次の呼び出しを実行させるのではなく、終了時間の間に一定間隔を置くことを好みます。私は常に呼び出しを均等に配置したいと思います。だから、私はそれを見ているように、これは問題を避けているようには見えません。 – matanster

+1

@matanster:OK、時間がかかりすぎる* _ _ runs_も問題があります。 –

+0

正解、申し訳ありません。私は今、その意図を明示的に中心にして質問を編集しました。関連ドキュメントの引用の前に非常に暗黙のうちに申し訳ありません! – matanster

0

言い換えると:私は、実行の端部との間に一定の間隔を持っていると思います次回の開始時刻。

EHMを、ので、あなただけの希望:

while(true) { 
    doThing() 
    Thread.sleep(fixedTimeBetweenEndAndStart) 
} 

末尾再帰funstionでそれを持っていると通じ正しくThread.isInterrupted /中断した例外を処理するために、よりよいだろう。

4

あなたが理由定型のにしたくない述べてきたが、scheduleOnceを使用した簡単な俳優がこれを行うには良い方法である、と定型が悪いように見えるしません:

import akka.actor.{Actor, Props, ActorSystem} 
import scala.concurrent.duration._ 

val system = ActorSystem("MySystem") 
val interval = 3 seconds 
val actor = system.actorOf(Props(new Actor{ 
    override def preStart = self ! "Execute" 
    override def receive: Receive = { 
    case "Execute" => 
     println(s"Executing at ${System.currentTimeMillis()}") 
     context.system.scheduler.scheduleOnce(interval, self, "Execute")(context.dispatcher) 
    }})) 

非常に正確な結果を得るには数行のコードが必要です。

関連する問題