睡觉的演员?

时间:2009-08-03 20:05:35

标签: scala actor

让演员入睡最好的方法是什么?我将演员设置为代理,希望维护数据库的不同部分(包括从外部源获取数据)。由于多种原因(包括没有超载数据库或通信和一般负载问题),我希望演员在每个操作之间休眠。我正在看10个演员对象。

演员将无限运行,因为总会有新数据进入,或者坐在一张桌子里等待传播到数据库的其他部分等。想法是让数据库尽可能完整在任何时间点。

我可以使用无限循环执行此操作,并在每个循环结束时进行休眠,但根据http://www.scala-lang.org/node/242,actor会使用一个线程池,只要所有线程都被阻塞,它就会被扩展。所以我想每个actor中的Thread.sleep都是个坏主意,因为会不必要地浪费线程。

我可能有一个拥有自己的循环的中央演员,它会在时钟上向订阅者发送消息(比如异步事件时钟观察者)?

有没有人做过类似的事情或有任何建议?很抱歉有额外的(可能是多余的)信息。

干杯

4 个答案:

答案 0 :(得分:21)

在第一个答案中,Erlang有一个很好的观点,但它似乎消失了。您可以轻松地使用Scala actor执行与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

答案 1 :(得分:17)

没有必要明确地让actor进入睡眠状态:对每个actor使用loopreact意味着底层线程池将具有等待线程,而没有消息供actor处理。

如果您希望安排事件供您的actor处理,使用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)

然后,您的目标actor只需要实现适当的react循环来处理给定的消息。你没有必要让任何演员睡觉。

答案 2 :(得分:4)

来自lift-util的ActorPing(Apache许可证)有schedule和scheduleAtFixedRate来源: ActorPing.scala

来自scaladoc:

  

ActorPing对象使用特定时间间隔的给定消息来调度要ping的actor。 schedule方法返回一个ScheduledFuture对象,必要时可以取消该对象

答案 3 :(得分:2)

不幸的是,在oxbow_lakes的答案中有两个错误。

一个是简单的声明错误(长时间对时间:长),但第二个是更微妙的。

oxbow_lakes宣布运行

def run = actors.Scheduler.execute(f) 
然而,这会导致消息不时消失。那就是:它们已经预定但永远不会发送。声明以

运行
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帖子,但是无法保存(损坏?),但我没有权利发表评论。因此一个新职位。