C # asynchronous world [Top ],

Source: Internet
Author: User
Tags apm

C # asynchronous world [Top ],

The new advanced programmers may have used a lot of async and await, but have little knowledge about the previous Asynchronization. I plan to review the historical asynchronous process.

This article will focus on the async asynchronous mode.

APM

APM Asynchronous Programming Model, Asynchronous Programming Model

APM was available as early as C #1. Although not very familiar, I still have seen it. That is, the BeginXXX and EndXXX classes, and the BeginXXX return value is the IAsyncResult interface.

Before formally writing an APM example, we will first provide a SectionCode Synchronization:

// 1. Synchronization Method private void button#click (object sender, EventArgs e) {Debug. writeLine ("[Debug] Thread ID:" + Thread. currentThread. managedThreadId); var request = WebRequest. create ("https://github.com/"); // to better demonstrate the effect, we use a slow Internet request. getResponse (); // send the Debug request. writeLine ("[Debug] Thread ID:" + Thread. currentThread. managedThreadId); label1.Text = "finished! ";}

[Note] to better demonstrate the asynchronous effect, we use the winform program as an example. (Because winform always requires UI thread rendering interface, if it is occupied by UI threads, it will be in the "false" status)

【]

BeginGetResponse, the so-called APM asynchronous model of EndOfStream)

Private void button2_Click (object sender, EventArgs e) {// 1. APM asynchronous programming model, asynchronous Programming Model // C #1 [implements BeginXXX and EndXXX Based on the IAsyncResult interface] Debug. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId); var request = WebRequest. create (" https://github.com/ "); Request. beginGetResponse (new AsyncCallback (t => {var response = request. endGetResponse (t); // callback var stream = response after execution is complete. getResponseStream (); // get the returned data stream using (StreamReader reader = new StreamReader (stream) {StringBuilder sb = new StringBuilder (); while (! Reader. endOfStream) {var content = reader. readLine (); sb. append (content);} Debug. writeLine ("[Debug]" + sb. toString (). trim (). substring (0,100) + "... "); // only take the first 100 characters of the returned content for Debug. writeLine ("[Debug] asynchronous Thread ID:" + Thread. currentThread. managedThreadId); label1.Invoke (Action) () => {label1.Text = "finished! ";})); // Here cross-thread access to the UI requires processing}), null); Debug. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId );}

【]

(Below is the basic pseudo-code implementation)

public class MyWebRequest : IAsyncResult{    public object AsyncState    {        get { throw new NotImplementedException(); }    }    public WaitHandle AsyncWaitHandle    {        get { throw new NotImplementedException(); }    }    public bool CompletedSynchronously    {        get { throw new NotImplementedException(); }    }    public bool IsCompleted    {        get { throw new NotImplementedException(); }    }}

This is definitely not usable. At least there must be an attribute of the stored callback function. Below we will slightly modify it:

Then we can customize the APM asynchronous model: (paired in and End)

Public IAsyncResult MyBeginXX (AsyncCallback callback) {var asyncResult = new MyWebRequest (callback, null); var request = WebRequest. create ("https://github.com/"); new Thread () => // re-enable a Thread {using (StreamReader sr = new StreamReader (request. getResponse (). getResponseStream () {var str = sr. readToEnd (); asyncResult. setComplete (str); // set asynchronous result }}). start (); return asyncResult; // return an IAsyncResult} public string MyEndXX (IAsyncResult asyncResult) {MyWebRequest result = asyncResult as MyWebRequest; return result. result ;}

The call is as follows:

Private void button4_Click (object sender, EventArgs e) {Debug. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId); MyBeginXX (new AsyncCallback (t => {var result = MyEndXX (t); Debug. writeLine ("[Debug]" + result. trim (). substring (0,100) + "... "); Debug. writeLine ("[Debug] asynchronous Thread ID:" + Thread. currentThread. managedThreadId) ;})); Debug. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId );}

:

While (! AsyncResult. IsCompleted) // loop until asynchronous execution is completed (polling mode) {Thread. Sleep (100);} var stream2 = request. EndGetResponse (asyncResult). GetResponseStream ();

Or

AsyncResult. AsyncWaitHandle. WaitOne (); // stop the thread until the asynchronous completion (blocking wait) var stream2 = request. EndGetResponse (asyncResult). GetResponseStream ();

 

Supplement: if it is a common method, we can also use the delegate asynchronous: (BeginInvoke, EndInvoke)

Public void MyAction () {var func = new Func <string, string> (t => {Thread. sleep (2000); return "name:" + t + DateTime. now. toString () ;}); var asyncResult = func. beginInvoke ("Zhang San", t => {string str = func. endInvoke (t); Debug. writeLine (str) ;}, null );}
EAP

EAP Event-based Asynchronous Pattern

This mode follows C #2.

Let's look at an EAP example:

Private void button3_Click (object sender, EventArgs e) {Debug. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId); BackgroundWorker worker = new BackgroundWorker (); worker. doWork + = new DoWorkEventHandler (s1, s2) => {Thread. sleep (2000); Debug. writeLine ("[Debug] asynchronous Thread ID:" + Thread. currentThread. managedThreadId) ;}); // register an event to Implement Asynchronous worker. runWorkerAsync (this); Debug. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId );}

 

[] (Also does not block the UI Interface)

[Features]

  • Register callback functions using events
  • Execute asynchronous call using XXXAsync

The example is simple, but it is not as clear and transparent as compared with the APM mode. Why is this possible? What is event registration? Why does RunWorkerAsync trigger the registered function?

I feel like I think more...

Let's try to decompile the source code:

I just want to say, is this fun?

TAP

Task-based Asynchronous Pattern

So far, do we think the above APM and EAP asynchronous modes are easy to use? It seems that no problems have been found. Think about it again... if we have multiple asynchronous methods that need to be executed sequentially, and all the return values must be obtained (in the main process.

First, define three delegates:

public Func<string, string> func1(){    return new Func<string, string>(t =>    {        Thread.Sleep(2000);        return "name:" + t;    });}public Func<string, string> func2(){    return new Func<string, string>(t =>    {        Thread.Sleep(2000);        return "age:" + t;    });}public Func<string, string> func3(){    return new Func<string, string>(t =>    {        Thread.Sleep(2000);        return "sex:" + t;    });}

Then execute the command in a certain order:

Public void MyAction () {string str1 = string. empty, str2 = string. empty, str3 = string. empty; IAsyncResult asyncResult1 = null, asyncResult2 = null, asyncResult3 = null; asyncResult1 = func1 (). beginInvoke ("Zhang San", t => {str1 = func1 (). endInvoke (t); Debug. writeLine ("[Debug] asynchronous Thread ID:" + Thread. currentThread. managedThreadId); asyncResult2 = func2 (). beginInvoke ("26", a => {str2 = func2 (). endInvoke (a); Debug. writeLine ("[Debug] asynchronous Thread ID:" + Thread. currentThread. managedThreadId); asyncResult3 = func3 (). beginInvoke ("male", s => {str3 = func3 (). endInvoke (s); Debug. writeLine ("[Debug] asynchronous Thread ID:" + Thread. currentThread. managedThreadId) ;}, null); asyncResult1.AsyncWaitHandle. waitOne (); asyncResult2.AsyncWaitHandle. waitOne (); asyncResult3.AsyncWaitHandle. waitOne (); Debug. writeLine (str1 + str2 + str3 );}

It seems nothing except ugly and hard to read. But is that true?

Is asyncResult2 null?
It can be seen that asyncResult2 is not assigned a value before the first asynchronous operation is completed, and an exception is reported when asyncResult2 executes the asynchronous wait. In this way, we cannot control the three asynchronous functions and get the returned values after the execution is completed in a certain order. (There are other methods in theory, but the code will be more complicated)

 

Yes. Now our TAP is on the stage.

You only need to call the static method Run of the Task class to easily use Asynchronization.

Return Value:

Var task1 = Task <string>. run () => {Thread. sleep (1, 1500); Console. writeLine ("[Debug] task1 Thread ID:" + Thread. currentThread. managedThreadId); return "Zhang San" ;}); // other logic task1.Wait (); var value = task1.Result; // obtain the return value Console. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId );

Now we process the preceding asynchronous execution in order:

Console. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId); string str1 = string. empty, str2 = string. empty, str3 = string. empty; var task1 = Task. run () => {Thread. sleep (500); str1 = "Name: James,"; Console. writeLine ("[Debug] task1 Thread ID:" + Thread. currentThread. managedThreadId );}). continueWith (t => {Thread. sleep (500); str2 = "Age: 25,"; Console. writeLine ("[Debug] task2 Thread ID:" + Thread. currentThread. managedThreadId );}). continueWith (t => {Thread. sleep (500); str3 = "hobby: Sister"; Console. writeLine ("[Debug] task3 Thread ID:" + Thread. currentThread. managedThreadId) ;}); Thread. sleep (2500); // other logic code task1.Wait (); Debug. writeLine (str1 + str2 + str3); Console. writeLine ("[Debug] main Thread ID:" + Thread. currentThread. managedThreadId );

[]

We can see that all results are obtained and executed asynchronously in order. The logic of the code is very clear. If you feel that it is not very big, what would happen if 100 asynchronous methods need to be executed asynchronously in order? Asynchronous callback using APM requires at least 100 asynchronous callback nesting. The complexity of the code can be imagined.

 

Extended thinking
  • How WaitOne waits for completion

  • Why does Asynchronization improve performance?

  • Is there an inevitable relationship between the number of threads used and CPU usage?

 

Question 1: How WaitOne waits for completion

Before that, let's take a simple look at the multi-thread signal control AutoResetEvent class.

var _asyncWaitHandle = new AutoResetEvent(false);_asyncWaitHandle.WaitOne();

This code will keep waiting at WaitOne. Unless another thread executes the set Method of AutoResetEvent.

var _asyncWaitHandle = new AutoResetEvent(false);_asyncWaitHandle.Set();_asyncWaitHandle.WaitOne();

In this way, you can directly execute WaitOne. There is no waiting.

Now, do we know something about WaitOne wait in the APM asynchronous programming model. Let's go back and implement the asynchronous waiting of the custom Asynchronous Method.

Public class MyWebRequest: callback {// asynchronous callback function (delegate) private AsyncCallback _ asyncCallback; private AutoResetEvent _ callback; public MyWebRequest (AsyncCallback asyncCallback, object state) {_ asyncCallback = callback; _ asyncWaitHandle = new AutoResetEvent (false);} // set the public void SetComplete (string result) {Result = result; IsCompleted = true; _ asyncWaitHandle. set (); if (_ asyncCal Lback! = Null) {_ asyncCallback (this) ;}// return value of the asynchronous request public string Result {get; set ;}// gets the User-Defined Object, it limits or contains information about asynchronous operations. Public object AsyncState {get {throw new NotImplementedException () ;}// gets the System. Threading. WaitHandle used to wait for the asynchronous operation to complete. Public WaitHandle AsyncWaitHandle {// get {throw new NotImplementedException ();} get {return _ asyncWaitHandle;} // gets a value indicating whether the asynchronous operation is synchronized. Public bool CompletedSynchronously {get {throw new NotImplementedException () ;}// gets a value indicating whether the asynchronous operation has been completed. Public bool IsCompleted {get; private set ;}}

The red code is the newly added asynchronous wait.

[Procedure]

 

Question 2:Why does Asynchronization improve performance?

For example, the synchronization code:

Thread. Sleep (10000); // assume this is a method for accessing the database. Thread. Sleep (10000); // assume this is a method for accessing the FQ website.

This Code takes 20 seconds.

If it is asynchronous:

Var task = Task. run () => {Thread. sleep (10000); // suppose this is a method for accessing the database}); Thread. sleep (10000); // assume this is a method task for accessing the FQ website. wait ();

This takes 10 seconds. This saves 10 seconds.

If:

Var task = Task. Run () => {Thread. Sleep (10000); // assume this is a database access method}); task. Wait ();

There is no time-consuming code in asynchronous execution.

Or:

Var task = Task. run () => {Thread. sleep (10000); // suppose this is a method for accessing the database}); task. wait (); Thread. sleep (10000); // assume this is a method for accessing the FQ website.

After a time-consuming task is placed in an asynchronous wait, such code will not improve performance.

There is another situation:

If a single-core CPU is used for highly intensive operations, Asynchronization is meaningless. (Because the computation is very CPU-consuming, and the network request wait does not consume CPU)

 

Question 3:Is there an inevitable relationship between the number of threads used and CPU usage?

Answer.

Let's make a single-core hypothesis.

Case 1:

long num = 0;while (true){    num += new Random().Next(-100,100);    //Thread.Sleep(100);}

In single-core mode, we only start one thread to fill up your CPU.

Started eight times, the CPU of the eight processes is basically full.

Case 2:

More than one thousand threads, and the CPU usage is 0. As a result, we have come to the conclusion that there is no bound relationship between the number of threads used and CPU usage.

Even so, you cannot open the thread unlimitedly. Because:

  • The process of starting a new thread is resource-consuming. (However, the thread pool is used to reduce the resources consumed by enabling new threads)
  • Multi-thread switching also takes time.
  • Each thread occupies a certain amount of memory to save the thread context information.

 

Demo: http://pan.baidu.com/s/1slOxgnF

This article has been synchronized to the index directory: C # basic knowledge Consolidation

I do not know much about asynchronous programming, and it is very likely that there are many incorrect descriptions and opinions in this article.

Thank you for your correction.

For the purpose of mutual discussion, there is no intention of misleading everyone.

 

[Recommended]

Http://www.cnblogs.com/wisdomqq/archive/2012/03/26/2412349.html

Related Article

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.