如何安排在给定条件为真后结束的定期作业?

How to schedule a periodic job that ends after given condition is true?

我查看了 akka scheduler and the example here,它允许我安排周期性和单一任务。我需要创建一个具有以下签名的方法:

def doWhile(fn: => Unit, whileFn: => Boolean, period:Long) = {
  // while whileFn evaluates to true, repeat fn every period millisecs
}

我可以将 fn 包装在另一个方法 fnNew 中,该方法计算 whileFn 并在为真时执行 fn。然后我可以安排 fnNew 定期执行。但这似乎是一个糟糕的黑客攻击。我希望 fnNewwhileFn 计算为假时成为 "unscheduled"。正确的做法是什么?

编辑:我想避免使用显式参与者,并希望避免使用共享状态,如以下代码所示:

def doRegularly(fn: => Unit, periodMillis:Long) = 
    scheduler.schedule(0 seconds, periodMillis milliseconds)(fn)
def doWhile(fn: => Unit, whileFn: => Boolean, period:Long) = {
  var c:Option[Cancellable] = None
  c = Some(doRegularly(
            if (whileFn) fn 
            else {
               if (c.isDefined)  c.get.cancel
            }, period))
}

(具有共享值 c

docs 开始,您可以使用 cancel


//This will schedule to send the Tick-message
//to the tickActor after 0ms repeating every 50ms
val cancellable =
  system.scheduler.schedule(0 milliseconds,
    50 milliseconds,
    tickActor,
    Tick)</p>

<p>//This cancels further Ticks to be sent
cancellable.cancel()
</pre>
schedule 方法 returns 具有取消方法的类型 Cancellable 的对象。
我不确定,您打算如何使用 whileFn,但只要它 returns 为假,就调用 Cancellable 对象上的取消方法。 

我认为您可以利用 scheduleOnce 来完成您想要的 w/o 在 doWhile 的定义中共享状态。如果您这样定义 doWhile

def doWhile(fn: => Unit, whileFn: => Boolean, duration:FiniteDuration)(implicit sys:ActorSystem) {
  if (whileFn){
    fn
    sys.scheduler.scheduleOnce(duration)(doWhile(fn, whileFn, duration))(sys.dispatcher)
  }
} 

然后你可以,例如,用下面的代码调用它:

implicit val system = ActorSystem("SchedTest")        
var count = 1
doWhile(printAndInc, count <= 10, 1 second)

def printAndInc{
  println(s"count is $count")
  count += 1
}

如果你运行上面的代码,你会看到它打印出数字 1 到 10,中间有一个停顿。