Actor
Actors in Scala are a part of the Akka toolkit, a powerful concurrency and distributed computing library. Actors make it easier to write safe and efficient concurrent and parallel systems. The Actor Model provides a higher level of abstraction for writing concurrent and distributed systems, enabling you to think about your application in terms of actors sending messages to each other, rather than worrying about threads and locks.
Here's a basic tutorial on how to use actors in Scala with Akka.
Setting Up
First, you need to include Akka dependency in your project. If you're using sbt, add the following to your build.sbt file:
libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % "2.8.5"
Basic Concepts
- Actor System: The root level where actors live. It's a heavyweight structure that will allocate 1...N threads for your actors.
- Actor: Encapsulates state and behavior. Actors communicate by exchanging messages.
- Message: Immutable data that actors send to each other.
Creating Actors
Actors in Akka are created by defining actor behavior and spawning actors from an actor system.
Defining Actor Behavior
Actor behavior is defined by implementing the Behavior interface. Let's start with a simple example: an actor that says "Hello" when it receives a message.
First, define the messages your actor will handle. It's a good practice to define messages as case classes inside a companion object of your actor:
object Greeter {
final case class SayHello(name: String)
}
Next, define the actor behavior:
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
import Greeter.SayHello
object Greeter {
def apply(): Behavior[SayHello] = Behaviors.receive { (context, message) =>
println(s"Hello, ${message.name}!")
Behaviors.same
}
}
Spawning Actors
To use the actor, you must create an actor system and spawn an instance of your actor:
import akka.actor.typed.ActorSystem
object HelloAkka {
def main(args: Array[String]): Unit = {
val greeter: ActorSystem[SayHello] = ActorSystem(Greeter(), "greeter")
greeter ! SayHello("Akka")
}
}
This program will print "Hello, Akka!" to the console.
Handling Different Messages
Actors can handle different types of messages. Here's an example of how to extend our Greeter to handle different kinds of greetings:
object Greeter {
sealed trait Command
final case class SayHello(name: String) extends Command
final case class SayGoodbye(name: String) extends Command
object Greeter {
def apply(): Behavior[Command] = Behaviors.receive { (context, message) =>
message match {
case SayHello(name) =>
println(s"Hello, $name!")
Behaviors.same
case SayGoodbye(name) =>
println(s"Goodbye, $name!")
Behaviors.stopped // Stop this actor
}
}
}