在什么时候应该分割演员的行为

时间:2015-08-31 21:02:33

标签: akka

我对Akka完全不熟悉。当我将以前的类方法/行为拆分成akka消息时,我很难掌握。许多示例将收到的消息显示为一行 - println(“Howdy”)。

  1. 我们假设我想要做以下事情:
  2. 给定一组预定义的正则表达式
  3. 给出一本书中的句子输入流。每条消息都是一个句子。
  4. 对句子
  5. 执行正则表达
  6. 增加正则表达式的匹配和不匹配的数量
  7. 如果匹配,请执行HTTP发布句子。
  8. akka专家在他们的头脑中使用什么指导来解决这个问题?我会在这里将每个步骤作为单独的消息而不是几个方法调用吗?在我的脑海中,我唯一会使用akka消息的是#1(每条消息)和#6(阻止http调用)。这将使我对每个句子的处理实际上执行了相当多的工作(但非阻塞工作)。它是否类似于我决定使用异步而不是使用异步?对我来说,只有在我有机会进行阻止操作时才会这样。

2 个答案:

答案 0 :(得分:2)

我假设您要在actor中跟踪的状态是每个正则表达式的匹配数。

在这种情况下,如果您没有很多正则表达式,那么您的初始方法是有效的。如果你有很多,并且每个句子都经过每个表达式,你将在actor线程上执行大量的工作。这项工作在没有I / O的意义上是非阻塞的,但它实际上阻止了发送给这个actor的其他消息的进展,所以它在这个意义上是阻塞的。演员是单线程的,所以如果你有很多传入的句子,演员的邮箱就会开始增长。如果您使用无界邮箱(默认情况下),您最终将使用OOM。

一种解决方案是将正则表达式匹配发送到Future。但是,您不能与该未来共享actor状态(每个正则表达式的匹配计数),因为(通常情况下)它将导致竞争条件。为解决这个问题,未来的结果将向您的演员发送另一条消息,其中包含需要更新的计数。

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 */}
}

答案 1 :(得分:1)

我建议使用Akka进行设计的方法是首先确定问题中的状态。

让我们从那里开始:

  • 如果您有状态,请评估演员是否比同步和锁定更简单的方法
  • 如果您没有州,请评估您是否确实需要使用演员

如果你有状态,那么一个actor可能是合适的,因为它可以帮助确保你安全地处理对actor中状态的并发访问,并且它的容错机制将帮助你的应用程序恢复,如果该状态变得腐败导致应用程序错误。

在你的情况下,一个或两个简单的计数器可以使用Java的原子整数来处理,所以我实际上建议你使用基本类而不是actor。它比使用演员要简单得多。如果你想返回未来,可以使用Java8s CompletableFuture或Scala的concurrent.Future,结果将比使用actor更简单。

所有这些都说,如果你想使用演员,设计可能不会保证多个演员,因为你只有一个状态。

作为一般规则,你的演员应该只有一个责任 - 就像良好的面向对象设计一样。虽然您可能在单个actor中接受消息,但您可能仍决定将逻辑拆分为多个类。因此,您可能拥有“RegexActor”,然后您可能会使用策略模式实现“MatchBehavior”,以便在构造时传递RegexActor。

全部,我不认为你需要建立一堆演员 - 演员给你事物之间的异步界限,但你仍然可以从演员所具有的行为中使用优秀的OO中受益。演员有一条消息 - 处理书中的行 - 但它有一些行为可以在几个不同的类中组成。我会为该行为使用基本类,并在接收消息后让actor委托给其他类。

您希望事情变得简单 - 在使用actor时会丢失类型安全性并增加代码,因此我建议您确保使用它的充分理由 - 存在于并发环境中的状态或分发