Preliminary Study on WCF-28: concurrency in WCF, Preliminary Study on wcf-28 concurrency
UnderstandingWCFConcurrency mechanism in
- When you understand the WCF concurrency mechanism, you mustWCFPreliminary Study-27: WCFInstantiation inUnderstanding, because the concurrency feature in WCF is implemented along with the context of the Service instance. The instance Context Model of WCF can be set through the attributes of InstanceContext. concurrency in WCF refers to the ability of an instance context to process request messages, when you need to process multiple message requests in an instance context, concurrency occurs. Therefore, when the value of InstanceContextMode is PerSession or Single, concurrency occurs. In this case, we can set the value of ConcurrencyMode to control the mode in which the service processes messages concurrently.
- ConcurrencyMode specifies whether the service class supports single-thread or multi-thread operation mode. Has the following three values:
Understanding the relationship between the concurrency mode and the instance context Mode
- When our InstanceContextMode is set to PerSession, a client session model generates a context for the service instance. If our ConcurrencyMode value is set to Single, the service processes messages in serial mode. Because the concurrent mode adopts the single-thread mode, only one message is processed at a time, and the thread ID in the Context Model of the same instance is the same.
- When we set InstanceContextMode to PerSession and the ConcurrencyMode value to Multiple, the Service uses a multi-threaded processing model. That is to say, multiple threads will appear in the context of an instance to process message requests. This will greatly speed up the processing capability of the program, but it is not absolute. When the processing capability of a program increases, the server will be consumed. Therefore, when processing messages concurrently, we must limit the maximum processing capability. When using a multi-threaded model to process messages, ensure thread safety. (This part requires a friendly understanding of multiple threads)
- Under what circumstances will we encounter a situation where ConcurrencyMode is Reentrant? Single uses a Single-thread processing model. When the client calls the server method, it adds a lock to the method. If the server needs to generate a callback to the client at this time, the callback method uses the request/Response Message model. After the service calls the client, it tries to obtain the instance context model again to process the subsequent program logic, the instance context is locked, but the instance context is locked before. The instance context before callback can release the lock only after the message processing is complete, and the instance context after callback cannot obtain the lock, resulting in the operation will never be completed, resulting in a deadlock. In this case, you can set ConcurrencyMode to Reentrant to solve this problem. (You can also set ConcurrencyMode to Multiple to solve this problem, because the multi-thread processing model is used after setting to Multiple)
WCF
Concurrency model example in
Note: If you are not clear about Token Generation, refer to the blog post in this series.
- In this example, the combination model of InstanceContextMode = PerSession and ConcurrencyMode = Single is used, that is, a session generates an instance context, and one instance context has only one thread to process requests. We can describe the processing of this model by outputting the instance context and thread ID for processing the request. The reference code is as follows:
using System.ServiceModel; using System.Threading; namespace Service { [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)] public class SampleMethod:ISampleMethod { public string MethodOne(string msg) { OperationContext operationContext = OperationContext.Current; InstanceContext instanceContext = operationContext.InstanceContext; string info = "InstanceContext HashCode: " + instanceContext.GetHashCode().ToString(); System.Threading.Thread.Sleep(2000); return "You called MethodOne return message is: " + msg + "\n->" + info + "\n->ManagedThreadId:" +
Thread.CurrentThread.ManagedThreadId.ToString()+" "+System.DateTime.Now.ToString(); } public string MethodTwo(string msg) { OperationContext operationContext = OperationContext.Current; InstanceContext instanceContext = operationContext.InstanceContext; string info = "InstanceContext HashCode: " + instanceContext.GetHashCode().ToString(); System.Threading.Thread.Sleep(3000); return "You called MethodTwo return message is: " + msg + "\n->" + info + "\n->ManagedThreadId:" +
Thread.CurrentThread.ManagedThreadId.ToString() + " " + System.DateTime.Now.ToString(); } } }
The client must generate an asynchronous client (svcutil.Exe/Out:F:\SampleMethodClient.Cs/Config:F:\App.Confighttp:// Localhost: 1234/SampleMethod/a/tcv: Version35). The client reference code is as follows:
using System; namespace Client { class Program { static void Main(string[] args) { SampleMethodClient client1 = new SampleMethodClient(); client1.MethodOneCompleted += new EventHandler<MethodOneCompletedEventArgs>(client1_MethodOneCompleted); client1.MethodOneAsync("Client1 called MethodOne"); client1.MethodTwoCompleted += new EventHandler<MethodTwoCompletedEventArgs>(client1_MethodTwoCompleted); client1.MethodTwoAsync("Client1 called MethodTwo"); SampleMethodClient client2 = new SampleMethodClient(); client2.MethodOneCompleted += new EventHandler<MethodOneCompletedEventArgs>(client2_MethodOneCompleted); client2.MethodOneAsync("Client2 called MethodOne"); client2.MethodTwoCompleted += new EventHandler<MethodTwoCompletedEventArgs>(client2_MethodTwoCompleted); client2.MethodTwoAsync("Client2 called MethodTwo"); Console.Read(); } static void client2_MethodOneCompleted(object sender, MethodOneCompletedEventArgs e) { Console.WriteLine(e.Result.ToString()); } static void client2_MethodTwoCompleted(object sender, MethodTwoCompletedEventArgs e) { Console.WriteLine(e.Result.ToString()); } static void client1_MethodOneCompleted(object sender, MethodOneCompletedEventArgs e) { Console.WriteLine(e.Result.ToString()); } static void client1_MethodTwoCompleted(object sender, MethodTwoCompletedEventArgs e) { Console.WriteLine(e.Result.ToString()); } } }
Running result:
Result description:
Client1 processes MethodOne and MethodTwo at different time points, but the context ID and thread ID of the processed instance are consistent. This verifies the preceding combined processing model and the client generates two proxies,
Two sessions are established, so the context IDs of the instances of Client1 and Client2 are inconsistent.
- Next, we will use the combined model of InstanceContextMode = PerSession and ConcurrencyMode = Multiple to make the service process in multi-thread concurrency mode. The Code only needs to change the value of ConcurrencyMode to Multiple, And the rest remains unchanged, re-compile and run the program.
Running result:
Result description:
Client1 processes MethodOne and MethodTwo at different time points. Although the context ID of the processed instance is consistent, the thread ID is inconsistent, which verifies the preceding combined processing model, and because the client generates two proxies,
Two sessions are established, so the context IDs of the instances of Client1 and Client2 are inconsistent.