Why does asynchronous CTP work poorly?

I do not understand why await and async do not improve the performance of my code here as if they should .

Although I am skeptical, I thought that the compiler had to rewrite my method so that the loads would run in parallel ... but it seems like this is not really happening.
(I do understand that await and async do not create separate threads, however, the OS must download in parallel and call my code in the source thread - shouldn 't it?)

Am I using async and await incorrectly? What is the correct way to use them?

the code:

 using System; using System.Net; using System.Threading; using System.Threading.Tasks; static class Program { static int SumPageSizesSync(string[] uris) { int total = 0; var wc = new WebClient(); foreach (var uri in uris) { total += wc.DownloadData(uri).Length; Console.WriteLine("Received synchronized data..."); } return total; } static async Task<int> SumPageSizesAsync(string[] uris) { int total = 0; var wc = new WebClient(); foreach (var uri in uris) { var data = await wc.DownloadDataTaskAsync(uri); Console.WriteLine("Received async'd CTP data..."); total += data.Length; } return total; } static int SumPageSizesManual(string[] uris) { int total = 0; int remaining = 0; foreach (var uri in uris) { Interlocked.Increment(ref remaining); var wc = new WebClient(); wc.DownloadDataCompleted += (s, e) => { Console.WriteLine("Received manually async data..."); Interlocked.Add(ref total, e.Result.Length); Interlocked.Decrement(ref remaining); }; wc.DownloadDataAsync(new Uri(uri)); } while (remaining > 0) { Thread.Sleep(25); } return total; } static void Main(string[] args) { var uris = new string[] { // Just found a slow site, to demonstrate the problem :) "http://www.europeanchamber.com.cn/view/home", "http://www.europeanchamber.com.cn/view/home", "http://www.europeanchamber.com.cn/view/home", "http://www.europeanchamber.com.cn/view/home", "http://www.europeanchamber.com.cn/view/home", }; { var start = Environment.TickCount; SumPageSizesSync(uris); Console.WriteLine("Synchronous: {0} milliseconds", Environment.TickCount - start); } { var start = Environment.TickCount; SumPageSizesManual(uris); Console.WriteLine("Manual: {0} milliseconds", Environment.TickCount - start); } { var start = Environment.TickCount; SumPageSizesAsync(uris).Wait(); Console.WriteLine("Async CTP: {0} milliseconds", Environment.TickCount - start); } } } 

Conclusion:

 Received synchronized data... Received synchronized data... Received synchronized data... Received synchronized data... Received synchronized data... Synchronous: 14336 milliseconds Received manually async data... Received manually async data... Received manually async data... Received manually async data... Received manually async data... Manual: 8627 milliseconds // Almost twice as fast... Received async'd CTP data... Received async'd CTP data... Received async'd CTP data... Received async'd CTP data... Received async'd CTP data... Async CTP: 13073 milliseconds // Why so slow?? 
+6
source share
2 answers

Chris's answer is almost right, but introduces a race condition and synchronously blocks all tasks.

As a general rule, it is best not to use task continuations if you have await / async . Also, do not use WaitAny / WaitAll - the equivalents of async WhenAny and WhenAll .

I would write this as follows:

 static async Task<int> SumPageSizesAsync(IEnumerable<string> uris) { // Start one Task<byte[]> for each download. var tasks = uris.Select(uri => new WebClient().DownloadDataTaskAsync(uri)); // Asynchronously wait for them all to complete. var results = await TaskEx.WhenAll(tasks); // Calculate the sum. return results.Sum(result => result.Length); } 
+10
source

I may be reading your code incorrectly, but it looks like you are launching a background thread to read asynchronous messages, and then block it immediately, waiting for it to complete. Nothing about the "asynchronous" code of your code is asynchronous. Try the following:

 static async Task<int> SumPageSizesAsync(string[] uris) { int total = 0; var wc = new WebClient(); var tasks = new List<Task<byte[]>>(); foreach (var uri in uris) { tasks .Add(wc.DownloadDataTaskAsync(uri).ContinueWith(() => { total += data.Length; })); } Task.WaitAll(tasks); return total; } 

And use it this way:

  { var start = Environment.TickCount; await SumPageSizesAsync(uris); Console.WriteLine("Async CTP: {0} milliseconds", Environment.TickCount - start); } 

I could be mistaken - the asynchronous material is new, and I am not 100% familiar with it, but a similar time for synchronization seems to bear me.

+1
source

Source: https://habr.com/ru/post/906062/


All Articles