[英]Non-Blocking Timer Tasks and Akka Actors
请注意:尽管我更喜欢使用Akka的Java API的解决方案(这是我正在使用的解决方案),但我对任何可行的解决方案都感到满意,并且可能会想出如何将基于Scala的答案转换为Java语言。
我有一个具有许多演员的Akka应用程序,其中两个是Fizz
和Buzz
。 Fizz
演员可以接受两种类型的消息:
StartNewTimerTask
; 和 ResetAllTimerTasks
Buzz
演员仅接受DoItNow
消息。 这些参与者与系统其余部分之间的消息流如下:
StartNewTimerTask
消息发送给Fizz
参与者 Fizz
actor收到StartNewTimerTask
消息时,它都会创建并启动一个新的异步/非阻塞计时器,该计时器尝试运行8秒。 如果计时器结束(8秒),则将DoItNow
消息发送给Buzz
actor Fizz
演员可以接受任意数量的并发StartNewTimerTask
消息,因此,可以同时“管理”多个潜在的计时器,每个计时器都计入该8秒的神奇数字。 其他因此,如果20名演员StartNewTimerTask
消息的Fizz
演员都彼此,那么几秒钟内Fizz
演员将是“管理” 20无阻塞,在同一时间独立的定时器。 当这20个计时器中的每个计时器达到各自的8秒持续时间时,它们会向Buzz
actor发送20条独立的DoItNow
消息 Fizz
演员接收ResetAllTimerTasks
消息时,当前正在“进行中” 的所有计时器将被中断/取消(以使它们停止向下计数到8秒的持续时间,从而防止它们从发送DoItNow
消息Buzz
)。 因此,从上面的示例中借用,如果Fizz
actor在时间t=1
和t=3
之间收到了20条StartNewTimerTask
消息,则在t=10
可能已经过去了14个定时器并触发了DoItNow
消息,也许还有6个正在进行中。 如果Fizz
在那一刻接收到ResetAllTimerTasks
消息,它将停止这6个计时器的ResetAllTimerTasks
和触发消息,因此在此示例中Buzz
将仅接收14条DoItNow
消息 我知道Java 8 API(sans Akka)提倡扩展TimerTask
并将这些任务提交给Timer#scheduleAtFixedRate
方法,但是我不确定这是否与Akka完全冲突,或者是否有更好的方法来实现此功能Akka API。 迄今为止我最大的尝试:
// Groovy pseudo-code
class MyTimerTask extends TimerTask {
@Inject
ActorRef buzz
@Override
void run() {
// No op!
}
void completeTask() {
buzz.tell(new DoItNow(), null)
}
}
class Fizz extends UntypedAbstractActor {
@Inject
Timer timer
@Override
void onReceive(Object message) {
if(message in StartNewTimerTask) {
timer.scheduleAtFixedRate(new MyTimerTask(), 0, 8 * 1000)
} else if(message in ResetAllTimerTasks) {
timer.cancel()
}
}
}
class Buzz extends UntypedAbstractActor {
@Override
void onReceive(Object message) {
if(message in DoItNow) {
// Do something super cool now...
}
}
}
但是我认为我没有正确地管理计时器,也没有充分利用Akka调度程序/计时器API的全部潜能。 有什么想法吗?
考虑避开Java Timer
API,以支持Akka 2.5.4刚发布的新的actor定时器功能。 Actor计时器使Actor可以使用与其生命周期相关的一个或多个内部计时器来安排向其发送定期消息。 要使用Java访问此功能,只需更改Fizz
actor即可扩展AbstractActorWithTimers
。
下面的示例在Scala中(在Scala中,混合使用Timers
特性):
object Fizz {
private case object SendToBuzz
}
class Fizz(buzz: ActorRef) extends Actor with Timers {
import Fizz._
def receive = {
case StartNewTimerTask =>
val uuid = java.util.UUID.randomUUID
timers.startPeriodicTimer(uuid, SendToBuzz, 8.seconds)
case ResetAllTimerTasks =>
timers.cancelAll()
case SendToBuzz =>
buzz ! DoItNow
}
}
Fizz
actor处理StartNewTimerTask
消息时,它将启动一个新计时器,该计时器将每八秒向self
(即Fizz
actor)发送一次SendToBuzz
消息。 Fizz
处理SendToBuzz
消息时,会将DoItNow
消息发送给Buzz
actor。 Fizz
处理ResetAllTimerTasks
消息时,它将取消所有计时器。 Fizz
重新启动或停止,则其所有计时器都会自动取消。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.