问题 Akka演员成为关闭不可变状态的方法是否安全?


这里的目的是为需要在不使用可变状态的情况下调用外部服务(或一些昂贵但高度可缓存的操作)的actor实现一个非常简单的缓存。

class A extends Actor{
  def receive = {
    case GetCommand => 
      val response = callExternalService()
      context.become(receiveWithCache(response))
      context.system.scheduler.schedule(1 day, 1 day, self, InvalidateCache)
      sender ! response
  }
  def receiveWithCache(cachedResponse:R): PartialFunction[Any,Unit] = {
    case GetCommand => sender ! cachedResponse
    case InvalidateCache => context.unbecome
  }
}

我知道有更多高级方法可以实现这一点,其中包括可以在Akka模式页面中找到的完全成熟的CacheSystem,但在某些情况下确实不需要。

另外,如果使用变得像这样安全,知道答案是有趣的。


11556
2017-09-30 18:50


起源

期待自己的答案,因为这是非常优雅的。 - yan
为什么不关闭不可变状态是安全的? - Robin Green
1)我不认为不惜一切代价避免(本地)状态是合理的 - 请不要启发我,如果我遗漏了某些东西 - 并且2)使用匿名(部分)功能不会更好看 context.become 而不是一个方法? - Erik Allik
@ErikAllik 1)但不涉及费用。实际上,如果你避免使用可变的本地状态可能会更好,因为使用期货的方法分享它是不安全的。 2)也许它适用于这样一个简单的情况,但如果接收方法更复杂,我认为它看起来不会更好。 - Cristian Vrabie
很高兴知道,谢谢! - Erik Allik


答案:


据我所知,这种技术很健全,应该对你有好处。它实际上是一种更聪明的方式来避免变异 var response 在你的代码中。我在答案中恰巧使用了这种技巧 这里 来自Akka团队的Viktor似乎认为这是一个很好的解决方案。但有一件事,你可以改变:

def receiveWithCache(cachedResponse:R): PartialFunction[Any,Unit] = {
  case GetCommand => sender ! cachedResponse
  case InvalidateCache => context.unbecome
}

至:

def receiveWithCache(cachedResponse:R): Receive = {
  case GetCommand => sender ! cachedResponse
  case InvalidateCache => context.unbecome
}

Receive type是一个速记别名 PartialFunction[Any,Unit]


13
2017-09-30 19:31



这甚至是推荐的方式。扩展问题: become 不会留下演员的背景,所以它是完全安全的,即使是可变的状态。 - Roland Kuhn