-
Notifications
You must be signed in to change notification settings - Fork 1
SystemParameters
Text compliant with Leucine version 0.5.x, x >= 1 (minor differences with 0.5.0)
As with any library, there are some parameters that are needed during
operation which should not completely fixed by the library designer.
On the other hand, as a user of the library you do not want to
set or think of them all the time, certainly not at first use.
You expect the designer to provide you with reasonable defaults
and rightfully so. There parameters are collected in the trait
SystemParameters
. Normally you safely ignore these and expect
they to 'the right thing' but given the fact that you have
reached this page, you might want to start playing with them.
As said at the page ActorContext
,
each instance of ActorContext
is parameterized with some system
parameters. The signature of the class is:
/** Trait to define the parameters needed for the context and platform classes to run. */
trait SystemParameters :
/** Helper method for tracing while debugging. Wrap your debug lines in traceln() */
def traceln(s: => String): Unit
/** The natural time the system pauses when there are no tasks. The use is platform dependent. */
def idleThreadPause: FiniteDuration
/** The average thread load per core. Override to change. This is only used on multithreaded platforms. */
def threadsPerCore: Int
/** The prefix used in actor names for actors that are workers */
def workerPrefix: String
/** The character that will be used in the full name definitions of the actors. */
def familyPathSeparator: Char
/** Global maximum number of letters per mailbox. */
def maxMailboxSize: Int
/** The minimal number of poll loops (from the guard) for an actor to be considered silent. */
def silentStop: Int
an the default implementation that is used is:
/**
* Default parameters for the system you may use. If other values are needed, construct an instance
* of your own and initialize the ActorImplementation with that. You may of course also write a
* completely new ActorImplementation. To make use of tracing, use println(s) for example. */
object DefaultSystem extends SystemParameters :
def traceln(s: => String): Unit = ()
val idleThreadPause: FiniteDuration = 10.millis
val threadsPerCore: Int = 4
val workerPrefix: String = "#"
val familyPathSeparator: Char = '.'
val maxMailboxSize: Int = Int.MaxValue
val silentStop: Int = 3
These values should be good for every day use, but feel free to experiment with them.
The most likely candidate for a replacement is the traceln(..)
. Replacing the
empty implementation by println(s)
enables you to see every step the actor
system takes internally. So it produces a lot more information than trace
functions from the monitor does. Its primary goal is the debugging of the
Actor System itself, but it can serve other purposes as well.
The way you would go about is:
- Declare a new object that derives from
SystemParameters
- Define a new instance of
ActorContext
that uses these parameters - This this instance as a given in your own code.
For example, the new SystemParameters
object could be
object MySystem extends SystemParameters :
def traceln(s: => String): Unit = println(s) /* Trace the system */
val idleThreadPause: FiniteDuration = 10.millis
val threadsPerCore: Int = 1 /* Allow only one thread per code */
val workerPrefix: String = "#"
val familyPathSeparator: Char = '.'
val maxMailboxSize: Int = 100 /* Not more than 100 messages in the box */
val silentStop: Int = 3
then the ActorContext
implementation becomes:
val mySystem: ActorContext = ActorContext.DirectImplementation(MySystem)
and use it like:
given ActorContext = mySystem
Just to give an idea what system tracing might produce below please
find the output of the ticker we used before, adapted with the new
ActorContext
(and reduce the ticks to 5). Here is the complete code:
import scala.concurrent.duration.{FiniteDuration,DurationInt}
import s2a.leucine.actors.*
object MySystem extends SystemParameters :
def traceln(s: => String): Unit = println(s) /* Trace the system */
val idleThreadPause: FiniteDuration = 10.millis
val threadsPerCore: Int = 1 /* Allow only one thread per code */
val workerPrefix: String = "#"
val familyPathSeparator: Char = '.'
val maxMailboxSize: Int = 100 /* Not more than 100 messages in the box */
val silentStop: Int = 3
given ActorContext = ActorContext.ActorContexDirectImplementation(MySystem)
/* Simple ticker example */
class Ticker extends AcceptActor(Ticker,"Ticker") :
import Actor.Stop
/* In receive we handle the incoming letters. */
final protected def receive(letter: Letter, sender: Sender): Receive = (state: State) => {
/* In this example, we do not care about the letters that much, but more about the state. */
state match
case Ticker.Tick(value: Int) =>
/* Report that we are in the 'tick' state*/
println(s"tick = $value")
/* Send a new letter to myself to continue the work */
this ! Ticker.Work
/* Change the state to a new one. This is obligatory. */
Ticker.Tock(value+1)
case Ticker.Tock(value: Int) =>
/* Report that we are in the 'tock' state*/
println(s"tock = $value")
/* As long as we are below 10 we continue the work, otherwise we stop. */
if value<5 then this ! Ticker.Work else stop(Stop.Finish)
/* Change the state to a new one. This is obligatory. */
Ticker.Tick(value+1) }
object Ticker extends AcceptDefine :
/* The ticker only excepts one letter */
sealed trait Letter extends Actor.Letter[Actor]
case object Work extends Letter
/* This actor can be in two 'states' */
sealed trait State extends Actor.State
case class Tick(value: Int) extends State
case class Tock(value: Int) extends State
/* The initial state of of a state actor */
val initial: State = Ticker.Tick(0)
/* Main entry point for the demo. */
object Main :
/* Create the root of the tree. */
private val ticker = new Ticker
/* Main code entrance point */
def main(args: Array[String]): Unit =
/* Set the ticker to work. */
ticker ! Ticker.Work
/* Give it some time to complete */
Thread.sleep(200)
and this is the output
TRACE null/Start: Constructed Ticker
TRACE null/Start: initComplete()
TRACE null/Start: processTrigger(coreTask=true)
TRACE null/Start: processInit()
TRACE Ticker/Play: processLoop(init=true)
TRACE Ticker/Play: processExit(dropped=List())
TRACE Ticker/Pause: sendEnvelope(letter=Work, sender=s2a.leucine.actors.Actor$Anonymous$@496c5f00)
TRACE Ticker/Pause: processTrigger(coreTask=true)
TRACE Ticker/Pause: processPlay(reset=true)
TRACE Ticker/Play: processLoop(init=false)
TRACE Ticker/Play: processEnvelope(letter=Work, sender=s2a.leucine.actors.Actor$Anonymous$@496c5f00)
tick = 0
TRACE Ticker/Play: sendEnvelope(letter=Work, sender=Ticker@1cf19f59)
TRACE Ticker/Play: processTrigger(coreTask=true)
TRACE Ticker/Play: processExit(dropped=List())
TRACE Ticker/Play: processPlay(reset=true)
TRACE Ticker/Play: processLoop(init=false)
TRACE Ticker/Play: processEnvelope(letter=Work, sender=Ticker@1cf19f59)
tock = 1
TRACE Ticker/Play: sendEnvelope(letter=Work, sender=Ticker@1cf19f59)
TRACE Ticker/Play: processTrigger(coreTask=true)
TRACE Ticker/Play: processExit(dropped=List())
TRACE Ticker/Play: processPlay(reset=true)
TRACE Ticker/Play: processLoop(init=false)
TRACE Ticker/Play: processEnvelope(letter=Work, sender=Ticker@1cf19f59)
tick = 2
TRACE Ticker/Play: sendEnvelope(letter=Work, sender=Ticker@1cf19f59)
TRACE Ticker/Play: processTrigger(coreTask=true)
TRACE Ticker/Play: processExit(dropped=List())
TRACE Ticker/Play: processPlay(reset=true)
TRACE Ticker/Play: processLoop(init=false)
TRACE Ticker/Play: processEnvelope(letter=Work, sender=Ticker@1cf19f59)
tock = 3
TRACE Ticker/Play: sendEnvelope(letter=Work, sender=Ticker@1cf19f59)
TRACE Ticker/Play: processTrigger(coreTask=true)
TRACE Ticker/Play: processExit(dropped=List())
TRACE Ticker/Play: processPlay(reset=true)
TRACE Ticker/Play: processLoop(init=false)
TRACE Ticker/Play: processEnvelope(letter=Work, sender=Ticker@1cf19f59)
tick = 4
TRACE Ticker/Play: sendEnvelope(letter=Work, sender=Ticker@1cf19f59)
TRACE Ticker/Play: processTrigger(coreTask=true)
TRACE Ticker/Play: processExit(dropped=List())
TRACE Ticker/Play: processPlay(reset=true)
TRACE Ticker/Play: processLoop(init=false)
TRACE Ticker/Play: processEnvelope(letter=Work, sender=Ticker@1cf19f59)
tock = 5
TRACE Ticker/Play: stop(value=Finish)
TRACE Ticker/Play: stopWith(finish=true)
TRACE Ticker/Finish: processExit(dropped=List())
TRACE Ticker/Finish: processStop(dropped=List(), finish=true)
TRACE Ticker/Stop: processTerminate(complete=true)
The null/Start
are a consequence of calling the name during the object construction.
This field is not yet populated. See this in action in Scastie.
The long definition in Scastie:
given ActorContext = ActorContext.ActorContexDirectImplementation(MySystem)
will not be needed any more from version 0.5.1, then you can use:
given ActorContext = ActorContext.DirectImplementation(MySystem)