Scala Akka Actor如何仅处理最新消息
假设我正在向参与者发送消息,当它处理一条消息时,可能会出现多条消息。现在,当它准备好处理下一条消息时,我希望它只处理最新的消息,因为以前的消息已经过时了。我如何才能最好地实现这一点 使用scala Actors库,我可以通过首先从发件人处进行如下检查来实现这一点:Scala Akka Actor如何仅处理最新消息,scala,akka,Scala,Akka,假设我正在向参与者发送消息,当它处理一条消息时,可能会出现多条消息。现在,当它准备好处理下一条消息时,我希望它只处理最新的消息,因为以前的消息已经过时了。我如何才能最好地实现这一点 使用scala Actors库,我可以通过首先从发件人处进行如下检查来实现这一点: if (myActor.getState != Runnable) myActor ! message 但是我认为我不能在Akka系统中进行这样的测试您可以实现自己的邮箱,这种方法不会影响您的actor实现。有关在ac
if (myActor.getState != Runnable)
myActor ! message
但是我认为我不能在Akka系统中进行这样的测试您可以实现自己的邮箱,这种方法不会影响您的actor实现。有关在actor实现而不是自定义邮箱实现中进行更改的解决方案,请参阅 在
排队
上丢弃旧邮件的邮箱的实现:
package akka.actor.test
import akka.actor.{ ActorRef, ActorSystem }
import com.typesafe.config.Config
import akka.dispatch.{Envelope, MessageQueue}
class SingleMessageMailbox extends akka.dispatch.MailboxType {
// This constructor signature must exist, it will be called by Akka
def this(settings: ActorSystem.Settings, config: Config) = this()
// The create method is called to create the MessageQueue
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new MessageQueue {
val message = new java.util.concurrent.atomic.AtomicReference[Envelope]
final def cleanUp(owner: ActorRef, deadLetters: MessageQueue): Unit =
Option(message.get) foreach {deadLetters.enqueue(owner, _)}
def enqueue(receiver: ActorRef, handle: Envelope): Unit =
for {e <- Option(message.getAndSet(handle))}
receiver.asInstanceOf[InternalActorRef].
provider.deadLetters.
tell(DeadLetter(e.message, e.sender, receiver), e.sender)
def dequeue(): Envelope = message.getAndSet(null)
def numberOfMessages: Int = Option(message.get).size
def hasMessages: Boolean = message.get != null
}
}
用法:
object Test extends App {
import akka.actor._
import com.typesafe.config.ConfigFactory
// you should use your config file instead of ConfigFactory.parseString
val actorSystem: ActorSystem =
ActorSystem("default", ConfigFactory.parseString(
"""
akka.daemonic=on
myMailbox.mailbox-type = "akka.actor.test.SingleMessageMailbox"
"""))
class EchoActor extends Actor {
def receive = {
case m => println(m); Thread.sleep(500)
}
}
val actor = actorSystem.actorOf(Props[EchoActor].withMailbox("myMailbox"))
for {i <- 1 to 10} {
actor ! i
Thread.sleep(100)
}
Thread.sleep(1000)
}
对象测试扩展应用程序{
输入akka.actor_
导入com.typesafe.config.ConfigFactory
//您应该使用配置文件而不是ConfigFactory.parseString
val actorSystem:actorSystem=
ActorSystem(“默认”,ConfigFactory.parseString(
"""
akka.daemonic=on
myMailbox.mailbox-type=“akka.actor.test.SingleMessageMailbox”
"""))
类EchoActor扩展了EchoActor{
def接收={
案例m=>println(m);Thread.sleep(500)
}
}
val actor=actorSystem.actorOf(Props[EchoActor].withMailbox(“myMailbox”))
对于{i来说,根本不需要实现自己的邮箱
删除了大量文本,让这段代码自己说话:
// Either implement "equals" so that every job is unique (by default) or do another comparison in the match.
class Work
case class DoWork(work: Work)
class WorkerActor extends Actor {
// Left as an exercise for the reader, it clearly should do some work.
def perform(work: Work): Unit = ()
def lookingForWork: Receive = {
case w: Work =>
self forward DoWork(w)
context become prepareToDoWork(w)
}
def prepareToDoWork(work: Work): Receive = {
case DoWork(`work`) =>
// No new work, so perform this one
perform(work)
// Now we're ready to look for new work
context become lookingForWork
case DoWork(_) =>
// Discard work that we don't need to do anymore
case w2: Work =>
// Prepare to do this newer work instead
context become prepareToDoWork(w2)
}
//We start out as looking for work
def receive = lookingForWork
}
这意味着只有在邮箱中没有更新的工作时,才会执行工作。您试图确保哪些邮件处理保证?我相信Akka也有优先收件箱。这可能会满足您的要求,但这会导致以下问题:如何处理旧邮件?因此,您可以按照建议使用自定义收件箱,或者actor存储最后处理的消息的时间戳(必须存储在消息中)然后删除之前的所有消息。这是一个好主意,但在您的实现中存在一个缺陷:您不应该依赖于工作平等:让我们假设我们的邮箱中有2个工作s:a来自s1
和a来自s2
a来自s2
,DoWork(a)来自s1
DoWork(a)从s1
,从s2工作(a)。因此,我们将从s1处理a
,而不是从s2处理a
。因此,您应该删除有关发送方的信息或修复您的实现。在{a来自s1
,b来自s1
,a来自s2
)的情况下,这可能很重要.没错,我假设实现equals的人会考虑到一个工作项是唯一的。这不是一般意义上的观点。我会添加一个免责声明。我错了吗,或者在成为一个新的PrepareToWork之前你不需要自我转发DoWork(w2)?“留给读者作为练习”…你没有在LTH修过数学吗?
$ sbt run
1
[INFO] <dead letters log>
[INFO] <dead letters log>
[INFO] <dead letters log>
5
[INFO] <dead letters log>
[INFO] <dead letters log>
[INFO] <dead letters log>
[INFO] <dead letters log>
10
// Either implement "equals" so that every job is unique (by default) or do another comparison in the match.
class Work
case class DoWork(work: Work)
class WorkerActor extends Actor {
// Left as an exercise for the reader, it clearly should do some work.
def perform(work: Work): Unit = ()
def lookingForWork: Receive = {
case w: Work =>
self forward DoWork(w)
context become prepareToDoWork(w)
}
def prepareToDoWork(work: Work): Receive = {
case DoWork(`work`) =>
// No new work, so perform this one
perform(work)
// Now we're ready to look for new work
context become lookingForWork
case DoWork(_) =>
// Discard work that we don't need to do anymore
case w2: Work =>
// Prepare to do this newer work instead
context become prepareToDoWork(w2)
}
//We start out as looking for work
def receive = lookingForWork
}