Fixed a critical mistake
Erroneously used functional actor for mutable state. Changed actor style to OO from functional. Experimented with ask pattern to get final result
This commit is contained in:
parent
260aa0fdc4
commit
1abc30070c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.ammonite
|
||||||
|
.metals
|
55
ActorDemo.sc
55
ActorDemo.sc
@ -13,35 +13,47 @@ import akka.util.Timeout
|
|||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import akka.actor.typed.scaladsl.AskPattern._
|
import akka.actor.typed.scaladsl.AskPattern._
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
import akka.actor.typed.scaladsl.AbstractBehavior
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import scala.util.Success
|
||||||
|
import scala.util.Failure
|
||||||
|
import scala.concurrent.Await
|
||||||
|
import scala.concurrent.Future
|
||||||
|
|
||||||
object CounterActor {
|
object CounterActor {
|
||||||
|
final case class CounterResult(count: Int)
|
||||||
|
|
||||||
sealed trait Command
|
sealed trait Command
|
||||||
final case object IncCount extends Command
|
final case object IncCount extends Command
|
||||||
final case class CounterResult(count: Int)
|
final case class GetResult(sender: ActorRef[CounterResult]) extends Command
|
||||||
final case class GetResult(sender: ActorRef[RootActor.Command])
|
|
||||||
extends Command
|
|
||||||
|
|
||||||
var counter = 0
|
|
||||||
|
|
||||||
def apply(): Behavior[Command] =
|
def apply(): Behavior[Command] =
|
||||||
Behaviors.receive { (context, command) =>
|
Behaviors.setup(ctx => new CounterActor(ctx))
|
||||||
command match {
|
|
||||||
case IncCount => counter += 1
|
private class CounterActor(context: ActorContext[Command])
|
||||||
|
extends AbstractBehavior[Command](context) {
|
||||||
|
private var counter = 0 // encapsulated mutable state
|
||||||
|
override def onMessage(msg: Command): Behavior[Command] = {
|
||||||
|
msg match {
|
||||||
|
case IncCount =>
|
||||||
|
counter += 1
|
||||||
|
Behaviors.same
|
||||||
case GetResult(sender) =>
|
case GetResult(sender) =>
|
||||||
context.log.info(s"Value of counter is $counter");
|
context.log.info(s"Value of counter is $counter");
|
||||||
sender ! RootActor.Reply(counter)
|
sender ! CounterResult(counter)
|
||||||
|
Behaviors.same
|
||||||
}
|
}
|
||||||
|
|
||||||
Behaviors.same
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object RootActor {
|
object RootActor {
|
||||||
sealed trait Command
|
sealed trait Command
|
||||||
case class Reply[T](reply: T) extends Command
|
final case class Reply[T](reply: T) extends Command
|
||||||
case object Begin extends Command
|
final case object Begin extends Command
|
||||||
case object GetResult extends Command
|
final case class GetResult(repyTo: ActorRef[CounterActor.CounterResult])
|
||||||
|
extends Command
|
||||||
|
|
||||||
implicit val timeout: Timeout = 3.seconds
|
implicit val timeout: Timeout = 3.seconds
|
||||||
|
|
||||||
@ -63,10 +75,11 @@ object RootActor {
|
|||||||
counterActor ! CounterActor.IncCount
|
counterActor ! CounterActor.IncCount
|
||||||
counterActor ! CounterActor.IncCount
|
counterActor ! CounterActor.IncCount
|
||||||
|
|
||||||
case GetResult =>
|
case GetResult(replyTo) =>
|
||||||
counterActor ! CounterActor.GetResult(
|
counterActor ! CounterActor.GetResult(
|
||||||
context.self
|
replyTo
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
@ -77,13 +90,15 @@ object RootActor {
|
|||||||
|
|
||||||
@main
|
@main
|
||||||
def main() = {
|
def main() = {
|
||||||
implicit val rootActor =
|
implicit val system =
|
||||||
ActorSystem(RootActor(), "TestActors")
|
ActorSystem(RootActor(), "TestActors")
|
||||||
|
|
||||||
implicit val timeout: Timeout = 3.seconds
|
implicit val timeout: Timeout = 3.seconds
|
||||||
|
|
||||||
rootActor ! RootActor.Begin
|
system ! RootActor.Begin
|
||||||
rootActor ! RootActor.GetResult
|
// system ! RootActor.GetResult
|
||||||
|
|
||||||
Thread.sleep(1000)
|
val x: Future[CounterActor.CounterResult] =
|
||||||
|
system ? (ref => RootActor.GetResult(ref))
|
||||||
|
Await.result(x, 1.second)
|
||||||
}
|
}
|
||||||
|
16
README.md
16
README.md
@ -3,15 +3,15 @@
|
|||||||
An experiment to see how the actor model can be used to synchronize / encapsulate mutable state without the use of locks.
|
An experiment to see how the actor model can be used to synchronize / encapsulate mutable state without the use of locks.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
``` bash
|
|
||||||
|
```bash
|
||||||
./ActorsDemo.sc
|
./ActorsDemo.sc
|
||||||
```
|
```
|
||||||
|
|
||||||
Sample output:
|
Sample output:
|
||||||
|
|
||||||
|
```
|
||||||
|
13:02:58.966 [TestActors-akka.actor.default-dispatcher-3] INFO ammonite.$file.AkkaActorsDemo.ActorDemo$RootActor$ - --- Beginning ---
|
||||||
|
13:02:58.967 [TestActors-akka.actor.default-dispatcher-5] INFO ammonite.$file.AkkaActorsDemo.ActorDemo$CounterActor$CounterActor - Value of counter is 5
|
||||||
|
CounterResult(5)
|
||||||
```
|
```
|
||||||
22:11:47.473 [TestActors-akka.actor.default-dispatcher-3] INFO ammonite.$file.ActorDemo$RootActor$ - --- Beginning ---
|
|
||||||
|
|
||||||
22:11:47.475 [TestActors-akka.actor.default-dispatcher-6] INFO ammonite.$file.ActorDemo$CounterActor$ - Value of counter is 5
|
|
||||||
|
|
||||||
22:11:47.475 [TestActors-akka.actor.default-dispatcher-3] INFO ammonite.$file.ActorDemo$RootActor$ - Received message Reply(5)
|
|
||||||
```
|
|
Loading…
Reference in New Issue
Block a user