worldterminator
worldterminator

Reputation: 3066

Why akka actor is so different from thread

I have an actor to control GUI. To guarantee the instant response(No stuck on screen), I assign a PinnedDispatcher to this actor.

val system = ActorSystem("sys1")
def createMonitor(clients:Seq[ActorRef],init_QPS:Int) = system.actorOf(Props( new MonitorGUI) ).withDispatcher("my-pinned-dispatcher"))

The configuration file is like

my-pinned-dispatcher {
  executor = "thread-pool-executor"
  type = PinnedDispatcher
}

The actor program is like this

class MonitorGUI() extends Actor {
  val rate = 1000 milliseconds
  val scheduler = context.system.scheduler
  def receive = {

    case GUIRefresh =>
      GUI.refresh()
    case StartMonitor =>
      scheduler.schedule( rate + (300 milliseconds), rate ,self, GUIRefresh )
  }
}

The scheduler should invoke "refresh" every second. However when there are lots of other actors which do a lot of heavy computation(e.g. 98% CPU), the scheduler can not guarantee "refresh" every second. For example GUI gets stuck for 5 seconds. However a pure thread program is much more responsive than the actor program, like this:

new Thread(new Runnable {
  override def run(): Unit = {
    while (true){
      GUI.refresh
      Thread.sleep(1000)
    }
  }
}).start()

I wonder why thread and actor are so different. Because this actor should have its own thread. There should be no difference.

Upvotes: 2

Views: 313

Answers (1)

lmm
lmm

Reputation: 17431

Actors are not preemptible like threads; when an actor starts processing a message, it will continue processing until it finishes that message, and only then can another actor run. This is a design decision for the sake of high throughput (it eliminates context switches), but you need to be conscious of it when writing actor code.

Either ensure that processing for no single message runs for longer than your desired latency (perhaps by splitting up computations into small units and sending a new message to trigger off each step), or else use separate execution contexts / dispatchers for your compute-heavy actors and your latency-sensitive actors. (Ideally you might want to ensure that the total number of threads across both contexts is equal to the number of physical CPU cores, so that neither context's threads can block the other).

Upvotes: 2

Related Questions