Asp tutorial. net How to Implement Asynchronous Programming
For many people, Asynchronization is to use background threads to run time-consuming operations. Sometimes this is true, but not in most of our daily scenarios.
For example, we have the following requirement: Use httpwebrequest to request the content of a specified uri and then output it to the text domain on the interface. The synchronization code is easy to write:
1: private void btndownload_click (object sender, eventargs e) 2: {3: var request = httpwebrequest. create ("http://www.sina.com.cn"); 4: var response = request. getresponse (); 5: var stream = response. getresponsestream (); 6: using (streamreader reader = new streamreader (stream) 7: {8: var content = reader. readtoend (); 9: this.txt content. text = content; 10:} 11 :}
Right, very simple. But as mentioned in the previous article, the short program experience will be very poor. Especially when the uri points to a very large resource and the network is very slow, the interface will be suspended when you click the Download button to obtain the result.
Oh, now you think of Asynchronization. Recall the previous article. We found that as long as we put time-consuming operations on another thread for execution, our ui thread can continue to respond to user operations.
Implement Asynchronization using independent threads
If you write the following code:
1: private void btndownload_click (object sender, eventargs e) 2: {3: var downloadthread = new thread (download); 4: downloadthread. start (); 5:} 6: 7: private void download () 8: {9: var request = httpwebrequest. create ("http://www.sina.com.cn"); 10: var response = request. getresponse (); 11: var stream = response. getresponsestream (); 12: using (streamreader reader = new streamreader (stream) 13: {14: var content = reader. readtoend (); 15: this.txt content. text = content; 16:} 17 :}
Then, f5 runs. Unfortunately, an exception occurs here: we cannot update the ui attributes on a non-ui thread (for more details, refer to my article: winform two three things (3) control. invoke & control. begininvoke ). We temporarily ignore this exception (it will not appear in release mode, but this is not recommended ).
Oh, after you write the above Code, you will find that the ui is no longer blocked. I thought, asynchronous is just like this. After a while, you suddenly remembered in which book did you see that you should try not to declare the thread yourself, and the application uses the thread pool. If you search for msdn, change the above Code to the following:
1: private void btndownload_click (object sender, eventargs e) 2: {3: threadpool. queueuserworkitem (download); 4:} 5: 6: private void download () 7: {8: var request = httpwebrequest. create ("http://www.sina.com.cn"); 9: var response = request. getresponse (); 10: var stream = response. getresponsestream (); 11: using (streamreader reader = new streamreader (stream) 12: {13: var content = reader. readtoend (); 14: this.txt content. text = content; 15:} 16 :}
Well, it's easy to complete. You admire yourself a little. In such a short period of time, even the "advanced technology" of the thread pool is used. When you are complacent, one of your colleagues said: Your implementation method is very inefficient. The time-consuming operations here are io operations, not computing-intensive, do not assign a thread to it (although not accurate, I think so if I leave it alone ).
Your colleagues are right. For io operations (such as read/write disks, network transmission, and database tutorial queries), we do not need to use a thread for execution. Modern disks and other devices can work with the cpu at the same time. During this period of time, the cpu can do other things. After reading the data, the cpu can be involved after interruption. Therefore, although the above Code has built a responsive interface, it has created a thread that does nothing (this thread will be blocked during the time of network requests ). Therefore, if you want to implement Asynchronization, consider whether time-consuming operations are computing-intensive or io-intensive. Different operations require different policies. For Computing-intensive operations, you can use the above method: for example, you need to solve complicated equations. Whether to use a dedicated thread or a thread pool depends on the degree to which your operations are critical.
At this time, you are thinking again, not letting me use threads, but also letting me implement Asynchronization. What should I do? Microsoft has helped you think of this for a long time. in the. net framework, almost all io operations are provided with the synchronous and asynchronous versions. Microsoft also defines two asynchronous programming modes to simplify asynchronous usage:
Classic async pattern
This method provides two methods for asynchronous programming: for example, the read method of system. io. stream:
Public int read (byte [] buffer, int offset, int count );
It also provides two methods for asynchronous reading:
Public iasyncresult beginread (byte [] buffer, int offset, int count, asynccallback callback );
Public int endread (iasyncresult asyncresult );
The method that starts with in initiates an asynchronous operation. The method that starts with begin also receives an asynccallback type callback, which is executed after the asynchronous operation is completed. Then, we can call endread to obtain the asynchronous operation result. I will not elaborate more on the details of this mode. If you are interested, read chapter 26 and chapter 27 of clr via c # And 《. the description of the asynchronous mode in the. net design specification. Here I will use this mode to re-implement the above code snippet:
1: private static readonly int buffer_length = 1024; 2: 3: private void btndownload_click (object sender, eventargs e) 4: {5: var request = httpwebrequest. create (" http://www.sina.com.cn "); 6: request. begingetresponse (ar) =>{ 7: var response = request. endrequest (ar); 8: var stream = response. getresponsestream (); 9: readhelper (stream, 0); 10 :}, null); 11 :}12: 13: private void readhelper (stream, int offset) 14: {15: var buffer = new byte [buffer_length]; 16: stream. beginread (buffer, offset, buffer_length, (ar) => {17: var actualread = stream. endread (ar); 18: 19: if (actualread = buffer_length) 20: {21: var partialcontent = encoding. default. getstring (buffer); 22: update (partialcontent); 23: readhelper (stream, offset + buffer_length); 24:} 25: else 26: {27: var latestcontent = encoding. default. getstring (buffer, 0, actualread); 28: update (latestcontent); 29: stream. close (); 30 :}31 :}, null); 32:} 33: 34: private void update (string content) 35: {36: this. begininvoke (new action () => {this.txt content. text + = content ;})); 37 :}
Thanks to lambda expressions, I have reduced the number of method declarations and introduced many instance members. However, the above Code is still very difficult to understand. The simple synchronization code was rewritten into a segmented one, and we can no longer use using, so we need to display the write stream. close (). Oh, my code hasn't processed exceptions yet, which is a headache for me. In fact, it is very difficult to write a robust asynchronous code, and it is very difficult to debug. However, the above Code can not only create responsive interfaces, but also use threads more efficiently. In this asynchronous mode, the beginxxx method returns an iasyncresult object, which is also very effective in asynchronous programming. For more information about it, read this article: winform 2: three things (2) asynchronous operation.
In addition, because we cannot use the while loop here, it is not easy to read the complete content from the stream, we must replace a good loop result with a recursive call: readhelper.
Event-based async pattern (eap)
In addition to the preceding programming mode, the. net framework also provides event-based asynchronous programming mode. For example, many webclient methods provide asynchronous versions, such as downloadstring.
Synchronization version:
Public string downloadstring (string url );
Asynchronous version:
Public void downloadstringasync (string url );
Public event downloadstringcompleteeventhandler downloadstringcomplete;
(Please note that the two asynchronous programming modes and the naming of the tap method in the async ctp to be introduced in the future have certain rules for parameter passing, figuring out these rules will get twice the result with half the effort in asynchronous programming)