Repository navigation
ActorContext
Text compliant with Leucine version 0.7.x
All action takes place against the so called ActorContext, which should
always be available as a given. This context organizes the computation
for Actor just as the standard ExecutionContext for Future does.
At the same time this isolates you from the platform by having an
platform dependent implementation for the JVM, JS and Native.
Even if the platform is single threaded (like JS)
they still work as multithreaded to the user, as long as you do
not block in any actor. This is, by the way, a bad idea on a
multithreaded platform as well.
The signature of the ActorContext reads:
trait ActorContext extends PlatformContext, ExecutionContext, ContextParametersso it implements the standard ExecutionContext as well as the
Leucine specific methods in PlatformContext and the related ContextParameters.
For each supported platform (JVM, JS, Native) there exists a special ContextImplementation
which ensures every call is handled the correct way for that specific platform.
For the user this is nice to know, but not that relevant. What however
may be relevant is how the ActorContext itself is implemented by
for this ContextImplementation to get a so called ActorContext.Implementation.
Instances of such a class (which then expose the ActorContext interface
for use in your application) contain some parameters, the
SystemParameters you may tweak, how is demonstrated on
a separate page.
There also exists the possibility for the user to define an own
ActorContext.Implementation, for extra features. Per default two
are predefined:
-
ActorContext.DirectImplementation: This provides the execution environment for the different platforms where they run directly on (JVM, JS, Native) -
ActorContext.EmulatedImplementation: This provides an completely platform independent emulated execution environment.
The ActorContext.DirectImplementation can be selected by defining:
given ActorContext = ActorContext.systemon top of your package. Doing so provides an instance of ActorContext.DirectImplementation
with the default system parameters. This is usually the most performant
implementation, and is the one we use in all examples. It makes use
of threading, if available, and also makes sure the ActorGuard works
together with the platform properties.
Sometimes you want to be completely independent of the platform. To that end you can use an emulated version of the context:
given ActorContext = ActorContext.emulatedIt provides its own scheduler, takes care of the timers etc. This extra layer may come at a performance loss though, compared to an implementation that runs directly on the metal. Everything runs in one big loop on the main thread.
Before Scala Native became multithreaded, Leucine used a version of the emulator to make it run as if it where multithreaded. This appeared to run reasonably fast.
If you want to have extra functionality present in your context you can define
your own ActorContext.Implementation it must at least extend the traits:
-
SystemParameterstoMySystemParameters: if needed add you own parameters to the existing ones. -
ActorContexttoMyActorContext: if needed add your own methods to the existing ones. - use one of
ContextImplementationorContextEmulation. Defining your own is possible, but if not for an entirely new platform it does not make much sense.
Then you can define for example:
object MySystem extends MySystemParameters :
def mySetting: Int = 42
...
/** The default ActorImplementation for the users. */
class MyImplementation(val parameters: MySystemParameters) extends ContextImplementation, MyActorContext, MySystemParameters :
export parameters.*
def platform = ContextImplementation.platform
val mySystem: ActorContext = new MyImplementation(MySystem)and use this as given ActorContext.