16

俳優を眠らせる最良の方法は何ですか? データベースのさまざまな部分を維持したいエージェントとしてアクターをセットアップしました (外部ソースからのデータの取得を含む)。いくつかの理由 (データベースや通信に過負荷をかけないこと、一般的な負荷の問題など) から、各操作の間にアクターをスリープさせたいと考えています。10 個のアクター オブジェクトのようなものを見ています。

アクターはほぼ無限に実行されます。常に新しいデータが入ってくるか、データベースの他の部分に伝播されるのを待っているテーブルに座っているなどです。間に合います。

無限ループと各ループの最後でのスリープでこれを行うことができますが、http://www.scala-lang.org/node/242によると、アクターはすべてのスレッドがブロックされるたびに拡張されるスレッドプールを使用します. したがって、スレッドを不必要に浪費するため、各アクターの Thread.sleep は悪い考えだと思います。

おそらく、クロックでサブスクライバーにメッセージを送信する独自​​のループを持つ中央のアクターを使用できますか (非同期イベント クロック オブザーバーなど)。

誰かが同様のことをしたか、何か提案がありますか? 余分な(おそらく余分な)情報で申し訳ありません。

乾杯

ジョー

4

4 に答える 4

21

最初の回答でErlangに良い点がありましたが、消えたようです。Scala アクターを使用すると、同じ Erlang のようなトリックを簡単に実行できます。たとえば、スレッドを使用しないスケジューラを作成しましょう。

import actors.{Actor,TIMEOUT}

def scheduler(time: Long)(f: => Unit) = {
  def fixedRateLoop {
    Actor.reactWithin(time) {
      case TIMEOUT => f; fixedRateLoop
      case 'stop => 
    }
  }
  Actor.actor(fixedRateLoop)
}

テスト クライアント アクターを使用してテストしてみましょう (私は Scala REPL で正しく実行しました)。

case class Ping(t: Long)

import Actor._
val test = actor { loop {
  receiveWithin(3000) {
    case Ping(t) => println(t/1000)
    case TIMEOUT => println("TIMEOUT")
    case 'stop => exit
  }
} }

スケジューラを実行します。

import compat.Platform.currentTime
val sched = scheduler(2000) { test ! Ping(currentTime) }

そして、あなたはこのようなものを見るでしょう

scala> 1249383399
1249383401
1249383403
1249383405
1249383407

これは、スケジューラが予想どおり 2 秒ごとにメッセージを送信することを意味します。スケジューラーを停止しましょう:

sched ! 'stop

テスト クライアントがタイムアウトの報告を開始します。

scala> TIMEOUT
TIMEOUT
TIMEOUT

それもやめてください:

test ! 'stop
于 2009-08-04T11:00:10.817 に答える
17

アクターを明示的にスリープ状態にする必要はありません。アクターごとloopに andreactを使用すると、アクターが処理するメッセージがない間、基になるスレッド プールに待機中のスレッドが存在することになります。

アクターが処理するイベントをスケジュールする場合は、java.util.concurrentユーティリティのシングルスレッド スケジューラを使用すると非常に簡単です。

object Scheduler {
  import java.util.concurrent.Executors
  import scala.compat.Platform
  import java.util.concurrent.TimeUnit
  private lazy val sched = Executors.newSingleThreadScheduledExecutor();
  def schedule(f: => Unit, time: Long) {
    sched.schedule(new Runnable {
      def run = f
    }, time , TimeUnit.MILLISECONDS);
  }
}

これを拡張して定期的なタスクを実行することができ、次のように使用できます。

val execTime = //...  
Scheduler.schedule( { Actor.actor { target ! message }; () }, execTime)

ターゲット アクターはreact、指定されたメッセージを処理するための適切なループを実装する必要があります。アクターを眠らせる必要はありません。

于 2009-08-03T22:43:27.300 に答える
4

lift-util の ActorPing (Apache ライセンス) には schedule と scheduleAtFixedRate があります Source: ActorPing.scala

スカドックから:

ActorPing オブジェクトは、アクターが特定の間隔で特定のメッセージで ping されるようにスケジュールします。スケジュール メソッドは、必要に応じてキャンセルできる ScheduledFuture オブジェクトを返します。

于 2009-08-07T10:04:19.787 に答える
2

残念ながら、oxbow_lakes の回答には 2 つのエラーがあります。

1 つは単純な宣言ミス (長い時間 vs 時間: 長い) ですが、2 つ目はもっと微妙です。

oxbow_lakes は次のように実行を宣言します

def run = actors.Scheduler.execute(f) 

ただし、これにより、メッセージが時々消えることがあります。つまり、それらはスケジュールされていますが、決して送信されません。run as の宣言

def run = f

私のためにそれを修正しました。lift-util の ActorPing とまったく同じ方法で行われます。

スケジューラ コード全体は次のようになります。

object Scheduler {
    private lazy val sched = Executors.newSingleThreadedScheduledExecutor();
    def schedule(f: => Unit, time: Long) {
        sched.schedule(new Runnable {
          def run = f
        }, time - Platform.currentTime, TimeUnit.MILLISECONDS);
    }
}

oxbow_lakes の投稿を編集しようとしましたが、保存できませんでした (壊れていますか?)。まだコメントする権利がありません。というわけで新規投稿。

于 2011-11-11T21:16:43.687 に答える