我对 Akka 完全陌生。我很难掌握何时应该将过去的类方法/行为拆分为 akka 消息。许多示例都将收到的消息显示为一行 - println("Howdy")。
- 假设我想要执行以下操作:
- 给定一组预定义的正则表达式
- 给定书中句子的输入流。每条消息都是一个句子。
- 对句子执行正则表达式
- 正则表达式匹配和不匹配的增量计数
- 如果匹配,则执行 HTTP post 语句。
akka 专家在头脑中使用什么准则来解决这个问题?我是否会将此处的每个步骤设为单独的消息而不是多个方法调用?在我看来,我唯一会使用 akka 消息的事情是 #1(每条消息)和 #6(阻止 http 调用)。这将使我对每个句子的处理实际上执行了大量的工作(但非阻塞工作)。这是否类似于我决定使用异步而不是不使用异步?对我来说,只有当我有机会进行阻塞操作时才会出现这种情况。
最佳答案
我假设您想要在 Actor 中跟踪的状态是每个正则表达式的匹配数。
在这种情况下,如果您没有大量正则表达式,您的初始方法是有效的。如果你有很多,并且每个句子都经过每个表情,那么你将在 Actor 线程上执行大量工作。从没有 I/O 的意义上来说,这项工作是非阻塞的,但它实际上阻止了发送到该 actor 的其他消息的进度,因此从这个意义上说它是阻塞的。 Actor 是单线程的,所以如果你有很多传入的句子,Actor 的邮箱就会开始增长。如果您使用无限制的邮箱(默认),您最终会出现 OOM。
一种解决方案是将正则表达式匹配到 Future
。但是,您不能与该 future 共享参与者状态(即每个正则表达式的匹配计数),因为(在一般情况下)它将导致竞争条件。为了解决这个问题,您的 future 结果将向您的参与者发送另一条消息,其中包含需要更新的计数。
case class ProcessSentence(s: String)
case class ProcessParseResult(hits: mutable.Map[Regex,Int], s: String)
case class Publish(s: String)
class ParseActor {
val regexHits = Map("\\s+".r -> 0, "foo*".r -> 0)
def receive = {
case ProcessSentence(s) => Future(parseSentence(s, regexHits.keys)).pipeTo(self)
case ProcessParseResult(update, s) =>
// update regexHits map
if(update.values.sum > 0)
self ! Publish(s)
case Publish(s) => Future(/* send http request */)
}
def parseSentence(s: String, regexes: Seq[Regex]): Future[ProcessParseResult] =
Future{ /* match logic */}
}
关于akka - Actor 的行为应该在什么时候 split ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32319925/