Orleans creates only one instance of grain by default and executes it as a single-threaded model. If there are multiple instances of the same grain instance in Orleans, there will be concurrency conflicts, and the single-threaded execution model can completely avoid concurrency conflicts.
However, in a special scenario, some instances are required to create multiple instances or to meet performance requirements in a non-single-threaded execution mode.
How to support creating multiple instances
For those who understand load balancing, it is easy to load if the Web server supports stateless (distributed Sesson or cookie identification). Similarly, for grain, if it is stateless, creating any number of instances in the system is the same, there is no state synchronization problem.
So how do you support such a grain in Orleans?
Orleans provides [Statelessworker] attribute, labeled Statelessworker, Orleans automatically adjusts the number of instances of the grain to meet the needs of the system. For grain labeled Statelessworker, it is common to invoke other grain behaviors based on the parameters, and do not need to maintain any state.
When the number of grain instances marked as statelessworker is insufficient to respond to the current system's processing requests, Orleans automatically creates a new silo instance in the other grain (grain host container) in cluster to meet the processing needs of the system. When the system hotspot has passed, if the grain has been idle, it is a waste of system resources, Orleans will automatically release these unused grain resources. This approach is much like the way cloud computing is elastic in cloud computing.
How to support non-single-thread execution mode
The nature of distributed applications is parallelism, but parallelism brings more complexity. There are two ways to reduce this complexity
1. Single-threaded access to the internal state of the actor instance
No data is shared between 2.Actor, only interacting with messages
Single-threaded data access avoids data expropriation and greatly reduces the complexity of distributed applications. So Orleans default is single-threaded execution mode. But this mode of execution also leads to the possibility of deadlocks.
For example, a sends a message to B, and waits for B's response.
b After receiving the message, send a message to a B to start waiting for a response
A because a response to a B message is waiting before it is not able to process a new message from B
A and B wait between each other, resulting in a deadlock.
There is no concurrency conflict for 2 messages between A and B, and for this, Orleans provides a way to allow the grain to be executed in a non-single-threaded model. [Reentrant] Attribute, grain, which marks this attribute, allows multiple entry, that is, non-single-threaded model execution.
After marking [reentrant], we look at the example of a B before.
A sends a message to B, waiting for B's response
b After receiving the message, send a message to a B to start waiting for a response
A because [reentrant] is marked, you can accept and process the message from B, and a response is sent back to B after processing is finished.
b After receiving the response, complete its own process, return the response to a, complete the call
Orleans single-Threaded execution model