Case study: Copytoasync

Source: Internet
Author: User

Return to the series "task-based asynchronous mode--Comprehensive introduction"

Copying a stream to another stream is a useful and common operation. The Stream.copyto method has been added in. Net 4 to accommodate scenarios that require this functionality, such as downloading data at a specified URL:

 Public Static byte[] Downloaddata (stringURL) {    using(varRequest =webrequest.create (URL))using(varResponse =request. GetResponse ())using(varResponsestream =Response. GetResponseStream ())using(varresult =NewMemoryStream ())        {Responsestream.copyto (result); returnresult.    ToArray (); }}

To improve responsiveness and scalability, we want to use tap mode to implement the above features. You can try to do this as follows:

 Public Static Asynctask<byte[]> DownloadDataAsync (stringURL) {    using(varRequest =webrequest.create (URL)) {        return awaitTask.run (() =        {            using(varResponse =request. GetResponse ())using(varResponsestream =Response. GetResponseStream ())using(varresult =NewMemoryStream ())                {Responsestream.copyto (result); returnresult.            ToArray (); }        }    }}

This implementation, if used for the UI thread, improves responsiveness because it is out of the calling thread that downloads the data task from the network and copies the network stream to the memory stream that eventually turns the downloaded data into an array. However, the implementation has no effect on scalability because it is still performing synchronous I/O and blocking thread pool threads while waiting for data to be downloaded. Instead, we want the following function code:

 Public Static Asynctask<byte[]> DownloadDataAsync (stringURL) {    using(varRequest =webrequest.create (URL))using(varResponse =awaitrequest. Getresponseasync ())using(varResponsestream =Response. GetResponseStream ())using(varresult =NewMemoryStream ()) {        awaitResponsestream.copytoasync (Result); returnresult.    ToArray (); }}

Unfortunately, in. Net 4, the asynchronous Copytoasync method is missing, and only the stream class has a synchronous CopyTo method. Now we provide ourselves with an implementation:

 Public Static void CopyTo ( This stream source, Stream destination) {    varnewbyte[  0x1000];     int bytesread;      while 0 0     {        0, bytesread);}    }

To provide an asynchronous CopyTo implementation, we can use the compiler to implement tap capabilities and slightly modify this implementation:

 Public Static AsyncTask Copytoasync ( ThisStream source, stream destination) {    varBuffer =New byte[0x1000]; intBytesread;  while((Bytesread =awaitSource. Readasync (Buffer,0, buffer. Length)) >0)    {        awaitDestination. WriteAsync (Buffer,0, Bytesread); }}

Here we change the return type from void to task, replace read and write with Readasync and WriteAsync, and add context-sensitive await keyword prefixes before readasync and WriteAsync calls.. Net READASYCN and WriteAsync are not present in 4, but can be implemented based on Task.Factory.FromAsync, as described in the "Tasks and APM" section of the previous essay:

 Public Statictask<int>Readasync ( ThisStream Source,byte[] Buffer,intOffsetintcount) {    returntask<int>. Factory.fromasync (source. BeginRead, source. EndRead, buffer, offset, count,NULL);} Public StaticTask WriteAsync ( ThisStream destination,byte[] Buffer,intOffsetintcount) {    returnTask.Factory.FromAsync (destination. BeginWrite, destination. EndWrite, buffer, offset, count,NULL);}

With these methods, we can successfully implement the Copytoasync method. We can also add a cancellationtoken to the method to support the revocation request, and the cancellationtoken will be monitored after each read and write in the copy process (if Readasync and writeasync support revocation, CancellationToken can also be threaded into those calls):

 Public Static AsyncTask Copytoasync ( ThisStream source, stream destination, CancellationToken CancellationToken) {    varBuffer =New byte[0x1000]; intBytesread;  while((Bytesread =awaitSource. Readasync (Buffer,0, buffer. Length)) >0)    {        awaitDestination. WriteAsync (Buffer,0, Bytesread);    Cancellationtoken.throwifcancellationrequested (); }}

Note that this revocation is also useful in the CopyTo implementation of the synchronization, and the incoming cancellationtoken will enable revocation. The implementation relies on a removable object returned from the method, but it is too late for the implementation to receive the object, because when the synchronization call is complete, there is nothing left to cancel. 】

We've also added support for progress notifications, including how much data has been replicated to date:

 Public Static AsyncTask Copytoasync ( ThisStream source, stream destination, CancellationToken CancellationToken, IProgress<Long>progress) {    varBuffer =New byte[0x1000]; intBytesread; LongTotalread =0;  while((Bytesread =awaitSource. Readasync (Buffer,0, buffer. Length)) >0)    {        awaitDestination. WriteAsync (Buffer,0, Bytesread);        Cancellationtoken.throwifcancellationrequested (); Totalread+=Bytesread; Progress.    Report (Totalread); }}

With this approach, we can now fully implement our downloaddataasync approach, including adding Undo and progress Support:

 Public Static Asynctask<byte[]>DownloadDataAsync (stringURL, cancellationtoken cancellationtoken, IProgress<Long>progress) {    using(varRequest =webrequest.create (URL))using(varResponse =awaitrequest. Getresponseasync ())using(varResponsestream =Response. GetResponseStream ())using(varresult =NewMemoryStream ()) {        awaitResponsestream.copytoasync (result, cancellationtoken, progress); returnresult.    ToArray (); }}

It is also possible to make further optimizations to our copytoasync methods. For example, if we were to use two buffer instead of one, we could write the previously read data when we read the next piece of data, so if both reads and writes used asynchronous I/O would create a cross-delay:

 Public Static AsyncTask Copytoasync ( ThisStream source, stream destination) {    inti =0; varbuffers =New[] {New byte[0x1000],New byte[0x1000] }; Task Writetask=NULL;  while(true)    {        varReadtask = source. Readasync (Buffers[i],0, Buffers[i]. Length)) >0; if(Writetask! =NULL)awaitTask.whenall (Readtask, Writetask); intBytesread =awaitReadtask; if(Bytesread = =0) Break; Writetask= destination. WriteAsync (Buffers[i],0, Bytesread); I^=1;//Swap buffers    }}

Eliminating unnecessary context conversions is another optimization. As mentioned earlier, the default await when a task begins execution, it is transferred back to the current SynchronizationContext. In the case of copytoasynch implementation, it is not necessary to use such a conversion because we do not operate any UI state. We can play the task.configureawait advantage class to turn off this automatic conversion. To simplify, the implementation of the original asynchronous above is modified as follows:

 Public StaticTask Copytoasync ( ThisStream source, stream destination) {    varBuffer =New byte[0x1000]; intBytesread;  while((Bytesread =awaitsource. Readasync (Buffer,0, buffer. Length). Configureawait (false)) >0)    {        awaitDestination. WriteAsync (Buffer,0, Bytesread). Configureawait (false); }}
return to the series "task-based asynchronous mode--Comprehensive introduction"

The series is finally over, thank you for your support. Please continue to follow our blog, I will be a series of articles in succession.

TKB to Jane: http://www.cnblogs.com/farb/

qq:782762625

Welcome to communicate with you!

This article copyright belongs to the author and the blog Garden altogether, welcome reprint. Without the consent of the author, the original link and the author must be clearly marked on the article page, otherwise the right to pursue legal liability is reserved.
If you think this article is good or something, you can click on the "recommended" button in the lower right corner, because your support is my biggest motivation to continue writing and sharing!

Case study: Copytoasync

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.