Asynchronous programming in. NET (III)-Continuation passing style and implementation of Asynchronization Using yield

Source: Internet
Author: User

In the previous article, we watched the traditional asynchronous programming and realized that asynchronous programming is not simple. The traditional asynchronous method divides the originally compact code into two parts, which not only reduces the readability of the code, but also makes some basic program structures unusable, therefore, most developers are reluctant to accept the need to use Asynchronization. I would like to discuss it in this article. the NET world already has several class libraries that assist in asynchronous development. However, after thinking about it, I think that introducing some theoretical knowledge may be helpful for understanding the Later class libraries and the updated content. Today we will discuss the Continuation Passing Style (CPS ).

 

.

 

CPS
First, let's look at the following method:

1: public int Add (int a, int B)
2 :{
3: return a + B;
4 :}

We call it like this:

1: Print (Add (5, 6 ))
2:
3: public void Print (int result)
4 :{
5: Console. WriteLine (result );
6 :}

If we write the above Code in CPS mode, it looks like this:

1: public void Add (int a, int B, Action <int> continueWith)
2 :{
3: continueWith (a + B );
4 :}
5:
6: Add (5, 6, (ret) => Print (ret ));

It is as if we put the method back, we are no longer directly returning the results of the method; what we are doing now is to accept a delegate, which indicates what I will do after the calculation of this method, is the legendary continue. In this case, the Add continue is Print.

This is not just the sample code above. In a method, the statements executed after this statement can be called the continue of this statement.

 

CPS and Async
So someone may ask, what is the relationship between so many of them and Asynchronization? Yes, it has a lot to do with Asynchronization. Recall the previous article that the classic asynchronous mode is a method starting with Begin that initiates an asynchronous request and transmits a callback to this method ), after the asynchronous execution is complete, the callback will be executed. We can call this callback as the continue of the asynchronous request:

1: stream. BeginRead (buffer, 0, 1024, continueWith, null)

What is the purpose of this? Let's take a look at the asynchronous code we want to write. (Note: This is a pseudo code. Do not paste the Code directly to vs to run it without reading the article ):

1: var request = HttpWebRequest. Create ("http://www.google.com ");
2: var asyncResult1 = request. BeginGetResponse (...);
3: var response = request. EndGetResponse (asyncResult1 );
4: using (stream = response. GetResponseStream ())
5 :{
6: var asyncResult2 = stream. BeginRead (buffer, 0, 1024 ,...);
7: var actualRead = stream. EndRead (asyncResult2 );
8 :}

Yes, we want to write asynchronous code like synchronous. I hate so many callbacks, especially nested callbacks.

Refer to the discussion on CPS before, in the request. the code after BeginGetResponse is its continue. It would be nice if I could have a mechanism to get my continue and then call the continue after I finish executing it. Unfortunately, C # does not have the control operator call/cc like Scheme to get continue.

The idea seems to be broken here. But can we look at it from another angle? If we can add an identifier to the above Code: add an identifier to the place where each asynchronous request is initiated, and the part after the identifier is continue.

Var request = HttpWebRequest. Create ("http://www.google.com ");
Id 1 var asyncResult1 = request. BeginGetResponse (...);
Var response = request. EndGetResponse (asyncResult1 );
Using (stream = response. GetResponseStream ())
{
ID 2 var asyncResult2 = stream. BeginRead (buffer, 0, 1024 ,...);
Var actualRead = stream. EndRead (asyncResult2 );
}

When Id 1 is executed, return immediately, and remember that only ID 1 is executed in this execution. After the asynchronous request is complete, it knows that Id 1 was executed last time, at this time, the execution starts from the next line of Id 1. When ID 2 is executed, an asynchronous request is encountered, and an asynchronous request is returned immediately. Remember that this execution has reached ID 2, after the request is completed, the execution will be resumed from the next line of ID 2. The current task is to identify it and how to resume execution from the mark position after the asynchronous request is complete.

Yield and Asynchronization
If you are familiar with the iterator feature added to C #2.0, you will find that yield is something we can use to identify. See the following code:

1: public IEnumerator <int> Demo ()
2 :{
3: // code 1
4: yield return 1;
5: // code 2
6: yield return 2;
7: // code 3
8: yield return 3;
9 :}

 

After compilation, code similar to the following will be generated (the pseudocode is very different, but the meaning is similar. You can open Reflector to view details ):

1: public IEnumerator <int> Demo ()
2 :{
3: return new GeneratedEnumerator ();
4 :}
5:
6: public class GeneratedEnumerator
7 :{
8: private int state = 0;
9:
10: private int currentValue = 0;
11:
12: public bool MoveNext ()
13 :{
14: switch (state)
15 :{
16: case 0:
17: // code 1
18: currentValue = 1;
19: state = 1;
20: return true;
21: case 1:
22: // code 2
23: currentValue = 2;
24: state = 2;
25: return true;
26: case 2:
27: // code 3
28: currentValue = 3;
29: state = 3;
30: return true;
31: default: return false;
32 :}
33 :}
34:
35: public int Current {get {return currentValue ;}}
36 :}

 

 

Yes, the C # compiler translates it into a state machine. Yield return is like a lot of markup. MoveNext executes the code before the next yield return every time it is called, and then returns immediately.

Okay. Now the marking function is available. How can we restore the call after the asynchronous request is executed? Through the above Code, you may have thought of it. Here we only need to call MoveNext again to restore the call. That status opportunity will help us deal with everything.

Then we transform our asynchronous code:

1: public IEnumerator <int> Download ()
2 :{
3: var request = HttpWebRequest. Create ("http://www.google.co

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.