Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to parse asynchronous programming In .NET APM/EAP and async/await

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

How to parse asynchronous programming In .NET APM/EAP and async/await, I believe that many inexperienced people do not know what to do, so this article summarizes the causes of the problem and solutions, through this article I hope you can solve this problem.

Overview

After writing a previous article about the past and present lives of async and await, it seems that there are still some questions about async and await improving the processing power of the website, and the blog Park itself has made a lot of attempts. Today we will answer this question again, and we will try async and await in WinForm, and compare the difference between the asynchronous programming mode APM/EAP and async/await before 4.5. we will also explore the problem of interacting between different threads.

IIS has a problem with processing power, but WinForm is a problem with UI response, and the UI thread of WinForm is the same from beginning to end, so there is a certain difference between the two. Some people may ask, does anyone still write WinForm? Well, it's really an old thing, not as cool as WPF, and not as advanced as WPF, but architecturally speaking, whether it's Web, WinForm, or WPF,Mobile, these are just presentation layers, aren't they? Today's large-scale systems are generally involved in desktop clients, Web clients, mobile phones and tablets, which is why there is an application layer and a service layer. The ASP.NET MVC,WinForm,WFP,Android/IOS/WP we are talking about here is the presentation layer. In the presentation layer, we should only deal with the logic related to "performance", and any business-related logic should be handled at the lower level. On the issue of architecture, we'll go deeper later, and not to mention that I didn't remind you, we'll see another aging technology in .NET today, Web Service.

I also have to remind you that the content of the article is a little long, and there are many knowledge points involved, so I recommend: "top first and then read". It is the way to read a long story in the 21st century and the beginning of good communication. Do you want to know what makes you different? Want to know why it is raining so hard in Shanghai today? Please remember to top first and then read, what you support is not my article, but our valuable spirit of going to work in spite of the heavy rain! Top first and then look, you deserve it!

How to improve the processing capacity of IIS by async/await

First of all, the response ability does not entirely mean the problem of the performance of our program. Sometimes your program may not have any problems and has been carefully optimized, but the response ability has not been improved. Website performance analysis is a complex task. Sometimes better results can only be achieved by experience and constant trial. Of course, what we're talking about today is mainly the processing power of IIS, or perhaps the performance of IIS, but it's not the performance of the code itself. Even if async/await can improve the processing power of IIS, for users, the time from the initiation of the request to the completion of page rendering will not change much because of the addition of async/await.

In addition, asynchronous ASP.NET can not be done only by async/await. ASP.NET already has asynchronous Page in the era of Web Form, including ASP.NET MVC, isn't there also asynchronous Controller? Async/await is new and cool, but it just makes some improvements based on the old technology to make it easier for programmers to write asynchronous code. People often say that Microsoft likes new bottles of old wine, at least we have to see what this new bottle brings to us, no matter any product, it is impossible to start very, so constantly iterative updates, it can also be said to be the right way to do things.

Steps of ASP.NET parallel processing

The article on how ASP.NET works in IIS has described in great detail how a request is processed from the client to the server HTTP.SYS*** into CLR (it is strongly recommended that students who do not understand this area read this article first to help you understand this section), but all the steps are based on the assumption of a thread. IIS itself is a multithreaded work environment, so what happens if we look at it from a multithreaded perspective? Let's first take a look at the following picture. Note: our next steps are based on the post-IIS7.0 integration pattern.

Let's sort out the above steps again:

All requests are initially received by HTTP.SYS. There is a queue within HTTP.SYS that maintains these requests. When the number of request in this queue is greater than a certain number (default is 1000), HTTP.SYS will directly return the status of 503 (server busy). This is our valve.

HTTP.SYS hands the request to the IO thread in the CLR thread pool

The Worker thread in the CLR thread pool receives the request from the IO thread for processing, and instead of waiting for the result of the request, the IO thread can return to continue processing the request in the HTTP.SYS queue. The upper limit for the number of IO and Worker threads is the second valve.

When the request data being processed in CLR is greater than a certain value (the number of requests processed in parallel), the requests from the IO thread will not be sent directly to the Worker thread, but will be placed in a queue at the process pool level. When the number is less than the critical value, it will be handed over to the Worker thread for processing again. This is our third valve.

What factors control our responsiveness?

From the several major valves mentioned above, we can conclude that the following digital controls or affect our response ability.

Length of the HTTP.SYS queue

* * number of IO threads and * number of Worker threads

* number of requests processed in parallel

Length of the HTTP.SYS queue

I don't think any additional explanation is needed. The default value is 1000. This value depends on the processing speed of the CLR IO thread and the Worker thread behind us, and it's no use if they can't handle both. Because * they will be stored in queues at the process pool level, they will only cause a waste of memory.

* * number of IO threads and * number of Worker threads

These two values can be configured in web.config.

MaxIoThreads: the number of * * IO threads requested from the HTTP.SYS queue

MaxWorkerThreads: the number of * Worker threads that actually handle requests in CLR

MinIoThreads: the minimum number of IO threads to get the request from the HTTP.SYS queue

Minimum number of Worker threads that actually process requests in minWorkerThreads:CLR

The default value for minIoThreads and minWorkerThreads is 1, and increasing them reasonably can avoid unnecessary thread creation and destruction. If the maxIoThreads setting is too large, or unreasonable, it will cause most request to be placed in the queue at the process pool level. So there is a certain relationship between maxIoThreads and maxWorkerThreads. Suppose a worker thread can handle 10 requests per second. If our machine configuration allows us to process only 100 requests at the same time, then our reasonable maxThreads is 10. But the IO thread does not need 10s to process a request, it is faster than the woker thread, because it only needs to be taken from the HTTP.SYS queue, we assume that an IO thread 1s can handle 20 requests, corresponding to the upper limit of 100s, then the reasonable value of our maxIoThreads should be 5.

* number of requests processed in parallel

The queue at the process pool level gives our CLR a certain buffer, and it should be noted that this queue has not yet entered the CLR, so it will not take up any resources in our managed environment, that is, blocking the request outside the CLR. We need to configure it at the aspnet.config level, which we can find in the. net fraemwork installation directory. It is usually C:\ Windows\ Microsoft.NET\ Framework\ v4.0.30319 if you install 4.0.

MaxConcurrentRequestPerCPU: the number of requests allowed to be processed in parallel per CPU. When the sum of requests being processed by worker threads in CLR is greater than this number, requests from IO threads will be placed in our process pool level queue.

MaxConcurrentThreadsPerCPU: set to 0 to disable.

RequestQueueLimit: this is the length of the queue in our HTTP.SYS, which we can configure under the web.config/system.web/processModel node.

What did async and await do?

We're finally going to get to the point. Take ASP.NET MVC, for example. If you don't use async's Action, there is no doubt that it is executed in a Woker thread. When we access some web service or read a file, the worker thread is blocked. Suppose the total execution time of our Action is 100ms, and other access web service takes 80ms. Ideally, a Worker thread can respond to 10 requests per second. Assuming that our maxWorkerThreads is 10, then we can always respond to requests within a second. What if we want to increase the number of responsible requests to 200?

Some people will say, this is not easy, can't you just adjust the maxWorkerThreads to 20? In fact, there is no problem with what we do, it is possible, and it can really work. Then why are we going to so much trouble with async/await? Are you out of your mind? What problem did async/await solve for us? It can release the current worker thread when we access the web service and put it back into the thread pool so that it can process other requests. Like the IO thread, the IO thread is only responsible for handing the request to the worker thread or putting it into a queue at the process pool level, and then going to the HTTP.SYS queue to process other requests. When web service returns the result to us, we will randomly pick up a new woker thread in the thread pool to continue to execute. In other words, we reduced that part of the waiting time and made full use of the thread.

Let's compare the use of async/awit with that of not.

Do not use async/await: 20 woker threads can handle 200 requests per second.

That translates to a total time of 20 * 1000ms = 20000ms.

The waiting time is 200 * 80ms = 16000ms.

In other words, we can save 16000ms time at least by using async/await, and these 20 worker threads will process requests again, even if we can add another 160 requests according to the processing time of each request 100ms. And don't forget that 100ms is obtained on the basis of synchronization, including waiting time, so the actual situation may be more. Of course, we do not take into account the thread switching time here, so there is a little difference in the actual situation, but it should not be very big, because our threads are based on thread pool operations.

The result is that when 20 Worker threads do not use asynchrony, 1s can handle 200 requests on its own, while in the case of async, it can handle 360 requests, an immediate increase of 80%! After adopting asynchronism, the amount of thread data needed for the same number of requests will be greatly reduced by about 50%. A thread will allocate at least 1m of memory on the heap, and if it is 1000 threads, that is 1G of capacity. Although memory is now cheap, it is good to save summary, and fewer threads can reduce the CPU consumption generated by thread pool when maintaining threads.

Note: the above data are not real test data, the time spent on a request is not 100ms, and the time spent on web service is not 80ms, it just gives you an idea:), so the improvement of response ability after using async and await has a lot to do with the time we originally blocked on these IO and networks.

A few suggestions

Seeing this, I don't know if you've got anything. First of all, the first thing we need to know is that async/await is not a drug, we can't expect to improve the performance just by writing two key words. Keep in mind that a CPU can only execute one thread at a time. So that's why async and await are recommended for IO or network operations. The scenario in which our MVC site accesses WCF or Web Service is ideal for using asynchrony. In the above example, most of the time for 80ms to read web service does not require cpu operation, so that cpu can be used by other threads. If it is not an operation to read web service, but a complex operation, then you are waiting for cpu to burst the table.

The second point is that in addition to the use of asynchrony in the program, the configuration of IIS mentioned above is very important, if you use asynchrony, please remember to increase the values of maxWorkerThreads and maxConcurrentRequestPerCPU.

The early asynchronous programming mode APM for Web service

After talking about our high-end async/await, let's take a look at Web Service, which is a very old technology, but the concept continues to this day. The asynchronous programming mode for web service we are talking about here does not refer to the web service itself on the server side, but to the client that invokes web service. As you know, for web service, we can generate the corresponding proxy class by adding a web service reference or the generation tool provided by. Net, which allows us to access web service as if we were calling native code, and the generated code class generates three corresponding methods for each web service method, for example, our method is called DownloadContent. In addition to this method, there are BeginDownloadContent and EndDownloadContent methods. And these are the early asynchronous programming patterns we're going to talk about today, APM (Asynchronous Programming Model). Let's take a look at the code in our web service and notice that our current projects are implemented under the .NET Framework3.5.

The code for PageContent.asmx

Public class PageContent: System.Web.Services.WebService {[WebMethod] public string DownloadContent (string url) {var client = new System.Net.WebClient (); return client.DownloadString (url);}}

Note that the DownloadContent method in our web service calls the synchronous method of WebClient, and WebClient also has an asynchronous method: DownloadStringAsync. But you have to understand that no matter whether the server is synchronous or asynchronous, it is the same for the client to call your web service, just waiting for you to return the result.

Of course, we can also write our server side asynchronously, just like the code in MVC. The benefit is the server that hosts web service, and its processing power is improved, just like ASP.NET. If we use JavaScript to call this Web Service, then Ajax (Asynchronous Javascript + XML) is the asynchronous programming technology used by our client. What if it's another client? Like a CS desktop program? Do we need asynchronous programming?

When WinForm meets Web Service,

Unlike ASP.NET sites hosted on IIS, WinForm has a thread pool that manages multiple threads to process user requests. In other words, ASP.NET sites are inherently multithreaded. However, in WinForm, if we do not deliberately use multithreading, there is only one thread, called the UI thread, from beginning to end. Perhaps in some small systems, WinForm rarely involves multithreading, because the advantage of WinForm itself is that it runs independently on the client side, and has great advantages in performance and maneuverability. So many small and medium-sized WinForm systems directly access the database, and basically only data transmission, what picture resources that is very few, so the waiting time is very short, basically no mental effort to think about what must be displayed in front of the user within 3 seconds.

Since WinForm has such a big performance advantage, does it still need to be asynchronous?

We are talking about small and medium-sized WinForm, what if it is a large system? What if WinForm is only a small part of the others, and as we begin to say, there are thousands of other mobile clients, Web clients, tablet clients? What if the database can't hold up because of so many clients? What if you want to add a layer of cache in the middle?

Take the website function of B2B, for example, users can place orders through the website, mobile phones can also place orders, and they can also place orders through the desktop client of the computer. After placing an order, we have to complete the functions such as transaction, inventory deduction, sending order confirmation notice, etc., no matter through which end your order is completed, we have to do these functions, right? Then we can't put it in WinForm alone, otherwise the code will have to be completely new and implemented one by one on other sides, and it would be quite dangerous to put the same code in different places, so we have our later SOA architecture, which extracts all these functions into services, and each type of side can just invoke the service. One is that these functions can be maintained uniformly, and the other is that it can be easily expanded to better adapt to the expansion of functions and architecture. For example, a system like the following.

In the figure above, although the web side belongs to what we usually call the server side (or even the web cluster composed of multiple servers), it is only one side to our entire system. For one end, it only deals with the problem of interaction with the user, and all other functions will be handed over to the later stage to handle. In our above architecture, the application layer will not directly participate in the processing related to the real business logic, but put it to our lower data layer for processing. Then the application layer mainly helps to do some functions that interact with users, such as SMS sending, email sending, etc., and can choose whether to put it in the queue for later processing or directly call the functional service to deal with it immediately according to the priority.

In such a system, either our Web server or our Winform side will be just a terminal in the whole system, and any of them is a bridge between the user and the following service. When it comes to the call to Service, in order to give users a good user experience, we naturally have to consider the problem of asynchronism on the Winform side.

WinForm calls Web Service asynchronously

With a powerful tool like VS to generate proxy classes for us, we can call Web Service like a local class library when we write code that calls Web service. We just need to add a Web Reference.

/ / the code of Form1.cs

Private void button1_Click (object sender, EventArgs e) {var pageContentService = new localhost.PageContent (); pageContentService.BeginDownloadContent ("http://jesse2013.cnblogs.com", new AsyncCallback (DownloadContentCallback), pageContentService);} private void DownloadContentCallback (IAsyncResult result) {var pageContentService = (localhost.PageContent) result.AsyncState; var msg = pageContentService.EndDownloadContent (result); MessageBox.Show (msg);}

The code is very simple. After executing the pageContentService.BeginDownloadContent, our main thread returns. Our UI will not be blocked or "unresponsive" during the call to Web service, and we can still drag the form or even do other things. This is the magic of APM, but in which thread does our callback execute? Is it a thread in the thread pool? Let's move on.

APM Asynchronous programming Mode explains Thread problem in detail

The next step is to take a closer look at how APM works, but first we have to answer the question that remains, does this asynchronous programming open up new threads for us? Let the code speak:

Private void button1_Click (object sender, EventArgs e) {Trace.TraceInformation ("Is current thread from thread pool? {0}", Thread.CurrentThread.IsThreadPoolThread? "Yes": "No"); Trace.TraceInformation ("Start calling web service on thread: {0}", Thread.CurrentThread.ManagedThreadId); var pageContentService = new localhost.PageContent (); pageContentService.BeginDownloadContent ("http://jesse2013.cnblogs.com", new AsyncCallback (DownloadContentCallback), pageContentService);} private void DownloadContentCallback (IAsyncResult result) {var pageContentService = (localhost.PageContent) result.AsyncState Var msg = pageContentService.EndDownloadContent (result); Trace.TraceInformation ("Is current thread from thread pool? {0}", Thread.CurrentThread.IsThreadPoolThread? "Yes": "No") Trace.TraceInformation ("End calling web service on thread: {0}, the result of the web service is: {1}", Thread.CurrentThread.ManagedThreadId, msg);}

We output the ID of the current thread and whether they belong to the thread pool in the button click method and the callback method, respectively. The result is as follows:

Desktop4.0.vshost.exe Information: 0: Is current thread a background thread? NO Desktop4.0.vshost.exe Information: 0: Is current thread from thread pool? NO Desktop4.0.vshost.exe Information: 0: Start calling web service on thread: 9 Desktop4.0.vshost.exe Information: 0: Is current thread a background thread? YES Desktop4.0.vshost.exe Information: 0: Is current thread from thread pool? YES Desktop4.0.vshost.exe Information: 0: End calling web service on thread: 14, the result of the web service is:...

The method of clicking the button is directly controlled by UI, which is obviously not a thread pool thread or a background thread. But our callback is executed in a backstage thread from the thread pool, the answer is revealed, but this will bring us a problem, we said above that only UI threads can update our UI controls, that is to say, we cannot update UI controls in callback, so how do we update UI to let users know feedback? The answer is later:), let's focus on figuring out APM.

Starting with Delegate

In fact, APM was widely used before .NET 3.5, in WinForm forms control, in a class library for IO operations, and so on! You can easily find a way to match Begin and End, and more importantly, we can use APM wherever there is an agent. Let's look at a very simple example:

Delegate void EatAsync (string food); private void button2_Click (object sender, EventArgs e) {var myAsync = new EatAsync (eat); Trace.TraceInformation ("Activate eating on thread: {0}", Thread.CurrentThread.ManagedThreadId); myAsync.BeginInvoke ("icecream", new AsyncCallback (clean), myAsync);} private void eat (string food) {Trace.TraceInformation ("I am eating...." On thread: {0} ", Thread.CurrentThread.ManagedThreadId);} private void clean (IAsyncResult asyncResult) {Trace.TraceInformation (" I am done eating....) On thread: {0} ", Thread.CurrentThread.ManagedThreadId);}

In the above code, we implement asynchronous execution by encapsulating the eat into a delegate and then calling the delegate's BeginInvoke method. That is, the actual eat method is not executed in the main thread, so we can look at the output:

Desktop4.0.vshost.exe Information: 0: Activate eating on thread: 10 Desktop4.0.vshost.exe Information: 0: I am eating.... On thread: 6 Desktop4.0.vshost.exe Information: 0: I am done eating.... On thread: 6

Clean is the callback we passed in, and this method will be called after our eat method is executed, so it will be called in the same thread as our eat method. If you are familiar with proxies, you will know that the code is actually compiled into a class, and the BeginInvoke and EndInvoke methods are the methods that the compiler adds automatically for us, and we don't have to do anything extra, which was a good choice before TPL and async/await (APM has been around since. Net 1.0).

Get to know APM again

Now that we know the BeginInvoke and EndInvoke of the Delegate implementation, let's take a look at the objects used by APM. Take our Web service proxy class as an example, which generates the following three methods for us:

String DownloadContent (string url): synchronization method

IAsyncResult BeginDownloadContent (string url, AsyncCallback callback, object asyncState): asynchronous start method

EndDownloadContent (IAsyncResult asyncResult): asynchronous end method

When we call the EndDownloadContent method, if our web service call has not yet returned, then we will use blocking to get the result. But by the time the callback we passed into BeginDownloadContent is called, the operation must have been completed, that is, IAsyncResult.IsCompleted = true. In APM asynchronous programming mode, the Begin method always returns the implementation of the IAsyncResult interface. IAsyncReuslt contains only the following four attributes:

WaitHanlde is usually the base class for synchronization objects and can be used to block threads. For more information, please refer to MSDN. With the help of IAsyncResult, we can obtain the results of what we are doing in the following ways.

Polling

Forced waiting

Completion notice

The completion notification is the kind you use above, and after calling the Begin method, the main thread completes the task. We do not need to monitor the execution of the operation, when the operation is completed, the callback we passed in the Begin method will be called, and we can call the End method in that method to get the result. Let's briefly talk about the first two ways.

/ / polling to get the result code

Var pageContentService = new localhost.PageContent (); IAsyncResult asyncResult = pageContentService.BeginDownloadContent ("http://jesse2013.cnblogs.com", null, pageContentService); while (! asyncResult.IsCompleted) {Thread.Sleep (100);} var content = pageContentService.EndDownloadContent (asyncResult)

/ / forced waiting for the result code

Var pageContentService = new localhost.PageContent (); IAsyncResult asyncResult = pageContentService.BeginDownloadContent ("http://jesse2013.cnblogs.com", null, pageContentService); / / you can also call the no-parameter version of WaitOne () without limiting the mandatory wait time if (asyncResult.AsyncWaitHandle.WaitOne (2000)) {var content = pageContentService.EndDownloadContent (asyncResult). } else {/ / 2s time has elapsed, but the execution of} EAP (Event-Based Asynchronous Pattern) is not finished.

EAP is another transitional asynchronous programming model introduced in. Net 2.0 and supported by Microsoft after. Net 3.5. Why? If you build a. Net 4.0 or higher WinForm project, and then add Web Reference, you will find that there are no Begin and End methods in the generated proxy class, remember that the two coexist in 3.5, you can choose either one to use. But after. Net 4. 0, EAP became your only option. (I haven't tried to generate proxy classes manually, students who are interested can try.) Let's take a look at how we call Web Service asynchronously under. Net 4.

Private void button1_Click (object sender, EventArgs e) {var pageContent = new localhost.PageContent (); pageContent.DownloadContentAsync ("http://jesse2013.cnblogs.com"); pageContent.DownloadContentCompleted + = pageContent_DownloadContentCompleted;} private void pageContent_DownloadContentCompleted (object sender, localhost.DownloadContentCompletedEventArgs e) {if (e.Error = = null) {textBox1.Text = e.Result } else {/ / error}} Thread problem

I don't know if you remember that in APM mode, callback is executed in another thread, and you can't update UI easily. But if you take a closer look at the above code, our DownloadContentCompleted event binding method directly updates the UI to write the returned content into a text box. In the same way, it can be found that in the asynchronous programming mode of EAP, the event-bound method is also executed in the calling thread. In other words, it solves the problem of UI interaction when asynchronous programming, and it is executed in the same thread. Look at the following code:

Private void button1_Click (object sender, EventArgs e) {Trace.TraceInformation ("Call DownloadContentAsync on thread: {0}", Thread.CurrentThread.ManagedThreadId); Trace.TraceInformation ("Is current from thread pool?: {0}", Thread.CurrentThread.IsThreadPoolThread? "YES": "NO"); var pageContent = new localhost.PageContent (); pageContent.DownloadContentAsync ("http://jesse2013.cnblogs.com"); pageContent.DownloadContentCompleted + = pageContent_DownloadContentCompleted;} private void pageContent_DownloadContentCompleted (object sender, localhost.DownloadContentCompletedEventArgs e) {Trace.TraceInformation (" Completed DownloadContentAsync on thread: {0} ", Thread.CurrentThread.ManagedThreadId); Trace.TraceInformation (" Is current from thread pool?: {0} ", Thread.CurrentThread.IsThreadPoolThread? "YES": "NO");} Desktop4.vshost.exe Information: 0: Call DownloadContentAsync on thread: 10 Desktop4.vshost.exe Information: 0: Is current from thread pool?: NO Desktop4.vshost.exe Information: 0: Completed DownloadContentAsync on thread: 10 Desktop4.vshost.exe Information: 0: Is current from thread pool?: what does NOasync/await bring to WinFrom

If async brings an increase in processing power to ASP.NET, then the benefits to programmers in WinForm are *. We no longer have to implement asynchronous write callbacks or bind events, which is easier and more readable. If you don't believe it, we will call our web service code to implement it under. Net 4.5:

Private async void button2_Click (object sender, EventArgs e) {var pageContent = new localhost.PageContentSoapClient (); var content = await pageContent.DownloadContentAsync ("http://jesse2013.cnblogs.com"); textBox1.Text = content.Body.DownloadContentResult;})

Simple three lines of code, write asynchronous code like synchronous code, I think maybe this is the magic of async/await. After the await, the UI thread can go back to respond to the UI. In the above code, there is no new thread generated, and we can directly operate on the UI just like the EAP.

Async/await seems really good, but what happens if the code behind our await is executed in another thread?

Private async void button1_Click (object sender, EventArgs e) {label1.Text = "Calculating Sqrt of 5000000"; button1.Enabled = false; progressBar1.Visible = true; double sqrt = await Task.Run (() = > {double result = 0; for (int I = 0; I)

< 50000000; i++) { result += Math.Sqrt(i); progressBar1.Maximum = 50000000; progressBar1.Value = i; } return result; }); progressBar1.Visible = false; button1.Enabled = true; label1.Text = "The sqrt of 50000000 is " + sqrt; } 我们在界面中放了一个ProgressBar,同时开一个线程去把从1到5000000的平方全部加起来,看起来是一个非常耗时的操作,于是我们用Task.Run开了一个新的线程去执行。(注:如果是纯运算的操作,多线程操作对性能没有多大帮助,我们这里主要是想给UI一个进度显示当前进行到哪一步了。)看起来没有什么问题,我们按F5运行吧! Bomb~ 当执行到这里的时候,程序就崩溃了,告诉我们"无效操作,只能从创建porgressBar的线程访问它。" 这也是我们一开始提到的,在WinForm程序中,只有UI主线程才能对UI进行操作,其它的线程是没有权限的。接下来我们就来看看,如果在WinForm中实现非UI线程对UI控制的更新操作。 不同线程之间通讯的问题***的Invoke WinForm中绝大多数的控件包括窗体在内都实现了Invoke方法,可以传入一个Delegate,这个Delegate将会被拥有那个控制的线程所调用,从而避免了跨线程访问的问题。 Trace.TraceInformation("UI Thread : {0}", Thread.CurrentThread.ManagedThreadId); double sqrt = await Task.Run(() =>

{Trace.TraceInformation ("Run calculation on thread: {0}", Thread.CurrentThread.ManagedThreadId); double result = 0; for (int I = 0; I)

< 50000000; i++) { result += Math.Sqrt(i); progressBar1.Invoke(new Action(() =>

{Trace.TraceInformation ("Update UI on thread: {0}", Thread.CurrentThread.ManagedThreadId); progressBar1.Maximum = 50000000; progressBar1.Value = I;} return result;}); Desktop.vshost.exe Information: 0: UI Thread: 9 Desktop.vshost.exe Information: 0: Run calculation on thread: 10 Desktop.vshost.exe Information: 0: Update UI on thread: 9

The Invoke method is relatively simple, so we won't do too much research, but we should consider that Invoke is a UI and interaction technology implemented by WinForm, while WPF uses Dispatcher. What if it is synchronization between threads under ASP.NET. In order to be compatible with the problem of cross-thread synchronization under various technology platforms, Microsoft introduced our following object in. Net 2.0.

SynchronizationContext context synchronization object

Why do you need SynchronizationContext

Just like the problems we encountered in WinForm, sometimes we need to pass some data in one thread or do something to another thread. But in most cases this is not allowed, and for security reasons, each thread has its own independent memory space and context. So in. Net 2.0, Microsoft launched SynchronizationContext.

One of its main functions is to provide us with a way to store some work tasks (Delegate) in a context object in a queue, and then associate these context objects to specific threads, of course, sometimes multiple threads can also be associated to the same SynchronizationContext object. SynchronizationContext.Current can be used to get the synchronization context object of the current thread. At the same time, it also provides us with the following two methods, Post and Send, which put the work tasks we mentioned above into our SynchronizationContext queue asynchronously and synchronously, respectively.

SynchronizationContext example

Let's take the example we used in Invoke above, but this time we don't directly call the control's Invoke method to update it, but write a Report method specifically to update UI.

Double sqrt = await Task.Run (() = > {Trace.TraceInformation ("Current thread id is: {0}", Thread.CurrentThread.ManagedThreadId); double result = 0; for (int I = 0; I)

< 50000000; i++) { result += Math.Sqrt(i); Report(new Tuple(50000000, i)); } return result; }); 每一次操作完之后我们调用一下Report方法,把我们总共要算的数字,以前当前正在计算的数字传给它就可以了。接下来就看我们的Report方法了。 private SynchronizationContext m_SynchronizationContext; private DateTime m_PreviousTime = DateTime.Now; public Form1() { InitializeComponent(); // 在全局保存当前UI线程的SynchronizationContext对象 m_SynchronizationContext = SynchronizationContext.Current; } public void Report(Tuple value) { DateTime now = DateTime.Now; if ((now - m_PreviousTime).Milliseconds >

{m_SynchronizationContext.Post ((obj) = > {Tuple minMax = (Tuple) obj; progressBar1.Maximum = minMax.Item1; progressBar1.Value = minMax.Item2;}, value); m_PreviousTime = now;}}

The whole operation looks a little more complex than Inovke, unlike Invoke, SynchronizationContext does not need a reference to Control, and Invoke must have that control before calling its Invoke method to update it.

Summary

The content of this blog is a little long. I don't know how many people can read it here:). At first, I just wanted to write something about asynchronously calling Web Service under WinFrom. At the beginning of this document, the title was "the practice of Asynchronous programming under WinForm", but it was written that more and more mysteries had not been solved, in fact, some old technologies had not been contacted and mastered well before, so fortunately, I relearned them all at once and shared them with you.

Let's review some of the important concepts involved in the article:

Async/await 's contribution to ASP.NET (as well as the earlier asynchronous development mode of ASP.NET) is that the current processing procedures are released in time when accessing the database and remote IO, and these threads can be returned to the thread pool to achieve the function of handling other requests.

How much improvement asynchronous ASP.NET development can bring in processing power depends on how much time our program is blocked, that is, the time it takes to access the database and remote Service.

In addition to changing the code to asynchronous, we also need to do some relative configuration on IIS to achieve *.

Whether it is ASP.NET, WinForm, Mobile, or tablet, it is only a side that interacts with users in large systems, so whether you are doing the so-called front end (JavaScript + CSS, etc.), the so-called back end (ASP.NET MVC, WCF, Web API, etc.), or the more fashionable mobile end (IOS, Andrioid, or even the disappointing WP), it is only a sporadic tip of the whole large system. Of course, I'm not belittling the value of these ends, just because we focus on differences and strive to improve the user experience on each side, so that these large systems have the opportunity to show up. What I want to say is that after you have made some achievements in current technology, don't stop learning, because there are still many wonderful things to discover in the whole software architecture.

APM and EAP are two different asynchronous programming modes before async/await.

If APM does not block the main thread, then the completion notification (callback) will be executed in another thread, thus causing some problems for us to update the UI.

The notification event of EAP is executed in the main thread and there is no problem with UI interaction.

We also learned about the problem of interaction between different threads under Winform, as well as SynchronizationContext.

APM is the earliest asynchronous programming method in .NET and has been available since. Net 1.0. In. Net 2.0, Microsoft realized the problem of interacting with UI in the callback function of APM, so it brought a new EAP. APM and EAP coexisted until .NET 3.5, when Microsoft brought TPL, also known as Task programming, in .NET 4.0, and .NET 4.5 is known as async/await. We can see that .NET has been constantly improving, coupled with recent cooperation with the open source community, the introduction of cross-platform and other features, we have reason to believe that .NET will get better and better.

After reading the above, have you learned how to parse asynchronous programming In .NET APM/EAP and async/await? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report