Summary of performance optimization (5): How to use multi-thread solutions on the csla Server

Source: Internet
Author: User

The previous article describes how to use Asynchronous threads to implement data pre-loading to improve system performance.

This operation is generally executed on the client to reduce user waiting time. After the client sends multiple asynchronous requests to the server, if the server does not support multi-threaded processing and processes each request linearly, the client's asynchronous requests will become meaningless.

We will certainly say, Who will design the server as a single thread? Isn't that an obvious error? Yes! However, our system uses csla as a distributed framework, and its serverProgramBut only supports single thread ...... We have been trying to solve this problem, but I have checked the official csla Forum. The author said that due to some reasons of globalcontext and clientcontext, multithreading is not supported for the moment. How can this be used! However, the system has already relied heavily on this framework. It is not realistic to change to a new one at half past one. So I had to manually modifyCodeNow:

 

Modify the WCF Communication Class

To change to a multi-threaded server, you must first start with the server's request processing .. The csla framework of net3.5 uses WCF for data transmission. It uses this class on the server side to receive:

Namespace csla. server. hosts {[servicebehavior (instancecontextmode = instancecontextmode. percall)] [invoke (requirementsmode = callback. Allowed)] public class wcfportal: iwcfportal {}}

As you can see, this class is not labeled concurrencymode = concurrencymode. Multiple and usesynchronizationcontext = false, so it has been designed for single-threaded operations. Here, we useDecoration ModeTo construct a new class:

/// <Summary> /// mark concurrencymode = concurrencymode. multiple // to indicate multithreading. // </Summary> [servicebehavior (instancecontextmode = instancecontextmode. percall, concurrencymode = concurrencymode. multiple, usesynchronizationcontext = false)] [aspnetcompatibilityrequirements (requirementsmode = aspnetcompatibilityrequirementsmode. allowed)] public class multithreadswcfportal: iwcfportal {private wcfportal _ innerportal = new wcfportal (); # region iwcfportal members public wcfresponse create (createrequest request) {return this. _ innerportal. create (request );}//... # endregion}

At the same time, we need to replace the code in both the configuration file and the class instantiation:

App. config:

<Services>
 
<! -- Csla. server. Hosts. wcfportal -->
 
<Service name = "openexpressapp. server. wpfhost. multithreadswcfportal" behaviorconfiguration = "returnfaults">... </service> </services>

 

Factory method:

Private Static type getserverhosttype () {return typeof (openexpressapp. server. wpfhost. multithreadswcfportal); // return typeof (csla. server. Hosts. wcfportal );}

In this way, when the server receives the request, multiple threads are automatically enabled to respond to the request. At the same time, the use of the decoration mode makes it unnecessary for usSource codeMake any changes.

 

Modify the applicationcontext. _ principal field

After modification according to the above operation, multiple threads have been implemented at the WCF level. However, when you run the application again, an nullrefrenceexception is thrown. The code appears here:

VaR currentidentity = csla. applicationcontext. User. Identity as oeaidentity; currentidentity. getdatapermissionexpr (businessobjectid );

After debugging, csla. applicationcontext. User is an unauthenticatedidentity instance. But we have logged on. Why is this attribute still "unauthorized? View the source code and findEach time at the beginning of request processing, csla sets this attribute as the user ID passed in by the client.. Let's look at the source code of this property in csla:

Private Static iprincipal _ principal; public static iprincipal user {get {iprincipal current; If (httpcontext. Current! = NULL) Current = httpcontext. Current. User; else if (system. Windows. application. Current! = NULL) {If (_ principal = NULL) {If (applicationcontext. authenticationtype! = "Windows") _ principal = new csla. security. unauthenticatedprincipal (); else _ principal = new windowsprincipal (windowsidentity. getcurrent ();} current = _ principal;} else current = thread. currentprincipal; Return Current;} set {If (httpcontext. current! = NULL) httpcontext. Current. User = value; else if (system. Windows. application. Current! = NULL) _ principal = value; thread. currentprincipal = value ;}}

The Code shows that if the server uses a WPF application, a static field is used to save the current user. This means that all threads on the server can only obtain the user of the last request. Of course, it cannot provide multi-threaded services! Here, it is actually a small bug of the author: He thinks thatThe WPF program should be a client, so it is directly stored in static variables.However, our server is also implemented by WPF, so we cannot use independent data for each thread.

This class is used by both the client and the server at the same time, so changes cannot affect the normal use of the client. To minimize changes to the original code, I changed the field code:

[Threadstatic] Private Static iprincipal _ principalthreadsafe; Private Static iprincipal _ principal {get {return _ executionlocation = executionlocations. Client? _ Principal: _ principalthreadsafe;} set {If (_ executionlocation = executionlocations. Client) {_ principal = value;} else {_ principalthreadsafe = value ;}}}

Here, the original field is changed to an attribute! When it is implemented, if it is on the client or a general static field is used. If it is on the server side, it is replaced with a field marked with [threadstatic], which indicates that this field will assign an independent value to each thread. In this way, when the server assigns a value to _ principal at the beginning of request processing, it is stored in the current thread without affecting other threads.

 

Manually enabled thread

Two problems have been solved above: 1. multithreading is not enabled by default; 2. When multiple threads assign values to the applicationcontext. User class, static fields are used to cause value conflicts.

Is it easy? The answer is no! :)

This only ensures that the applicationcontext. User attribute value is correct in the thread in which WCF is used to process requests. However, when processing a separate request, it is very likely that more threads are opened manually to serve it. The applicationcontext. User field of these threads is not assigned a value by the csla framework. If this field is used, nullrefrenceexception ......

Because the code we use for asynchronous processing is encapsulated in a subtle way, the benefits are presented at this time. Our solution is to add a "package" for the incoming Asynchronous Operation in the implementation of the method for manually applying for asynchronous execution. For example, the following API, it is used to call asynchronous operations for the client program. At that time, it only encapsulates simple calls to the thread pool to facilitate future extension (for example, we can change it to task to implement ......).

Public static void safeinvoke (action Action) {threadpool. queueuserworkitem (O => action ());}

We added an extension method as follows:

/// <Summary> /// the generated wrapper ensures that the new thread and main thread use the same prinel El before and after the action is executed. /// // Solve the problem: // due to applicationcontext. user is thread-based, // so if you open a new thread on the server side to do something in the same request, /// this newly opened thread may use different principle as the opener, resulting in code exceptions. /// </Summary> /// <Param name = "action"> /// operations that may use applicationcontext. User and need to be executed by another thread on the server. /// </Param> /// <returns> </returns> Public static action asynprinprinlewrapper (this action Action) {If (applicationcontext. executionlocation = applicationcontext. executionlocations. client) {Return Action;} var principelneed = applicationcontext. user; Return () => {var oldprincipel = applicationcontext. user; If (oldprincipel! = Principelneed) {applicationcontext. User = principelneed;} Try {Action ();} finally {If (oldprincipel! = Principelneed) {applicationcontext. User = oldprincipel ;}}};}

The original API is changed:

 
Public static void safeinvoke (action Action) {Action = action. asynprinciplewrapper (); threadpool. queueuserworkitem (O => action ());}

In this way, the applicationcontext. user of the manually opened thread is used.

Summary

This article describes how to build the csla framework server to support multithreading. It may be helpful for friends who use the csla framework.

The next article describes how to apply an instance in the gix4 ProjectArticle.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.