Why I should use context.become() to store internal state in Actor?

怎甘沉沦 提交于 2019-12-10 19:45:52

问题


I've read scala-best-practices and have a question about "5.2. SHOULD mutate state in actors only with context.become". I don't understand why it is so bad to store internal state using var. If actor executes all messages sequentially I just can't see any source of problems. What do I miss?


回答1:


Consider the first example in the article that you referenced:

class MyActor extends Actor {
  val isInSet = mutable.Set.empty[String]

  def receive = {
    case Add(key) =>
      isInSet += key

    case Contains(key) =>
      sender() ! isInSet(key)
  }
}

There's nothing inherently incorrect with this example, so there isn't some vital understanding that you're missing. As you know, an actor processes the messages in its mailbox sequentially, so it is safe to represent its state in an internal variable and to mutate this state, as long as the actor doesn't expose that state1.

become is often used to dynamically switch an actor's behavior (e.g., changing the kind of messages that the actor handles) and/or its state. In the second example in the article, the actor's state is encoded in its behavior as a parameter. This is an elegant alternative to the first example, but in this simple case it's a matter of preference.

One scenario in which become can really shine, however, is an actor that has many state transitions. Without the use of become, the actor's logic in its receive block can grow unmanageably large or turn into a jungle of if-else statements. As an example of using become to model state transitions, check out this sample project that models the "Dining Philosophers" problem.


1A potential issue is that while isInSet is a val, it's a mutable Set, so weird things can happen if the actor exposes this state to something outside of the actor itself (which it is not doing in the example). For example, if the actor sends this Set in a message to another actor, then the external actor can change this state, causing unexpected behavior or race conditions. One can mitigate this issue by changing the val to a var, and the mutable Set to an immutable Set.




回答2:


I don't think there's necessarily anything wrong with using vars in actors, for exactly the reasons you mentioned (Keep in mind though, that this is only for code executed in the context of the receive(...), i.e., if you start a thread, or use a Future, even if it's from within the receive, that code is no longer executed sequentially).

However, I personally prefer to use context.become(...) for controlling state, mainly because it clearly shows me the states in the actor that can change (vars can be scattered all over).

I also prefer to limit it to 0 or 1 call to context.become(...) per message handled, so it's clear where this state transition is happening.

That said, you can get the same benefits by using a convention where you define all your vars in one place, and make sure to re-assign them in one place (say towards the end) in your message handling.



来源:https://stackoverflow.com/questions/47589383/why-i-should-use-context-become-to-store-internal-state-in-actor

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!