Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use AsParallel with the async and await keywords?

Tags:

I was looking at someone sample code for async and noticed a few issues with the way it was implemented. Whilst looking at the code I wondered if it would be more efficient to loop through a list using as parallel, rather than just looping through the list normally.

As far as I can tell there is very little difference in performance, both use up every processor, and both talk around the same amount of time to completed.

This is the first way of doing it

var tasks= Client.GetClients().Select(async p => await p.Initialize()); 

And this is the second

var tasks = Client.GetClients().AsParallel().Select(async p => await p.Initialize()); 

Am I correct in assuming there is no difference between the two?

The full program can be found below

using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace ConsoleApplication2 {     class Program     {         static void Main(string[] args)         {             RunCode1();             Console.WriteLine("Here");             Console.ReadLine();              RunCode2();             Console.WriteLine("Here");              Console.ReadLine();          }          private async static void RunCode1()         {             Stopwatch myStopWatch = new Stopwatch();             myStopWatch.Start();              var tasks= Client.GetClients().Select(async p => await p.Initialize());              Task.WaitAll(tasks.ToArray());             Console.WriteLine("Time ellapsed(ms): " + myStopWatch.ElapsedMilliseconds);             myStopWatch.Stop();         }         private async static void RunCode2()         {             Stopwatch myStopWatch = new Stopwatch();             myStopWatch.Start();             var tasks = Client.GetClients().AsParallel().Select(async p => await p.Initialize());             Task.WaitAll(tasks.ToArray());             Console.WriteLine("Time ellapsed(ms): " + myStopWatch.ElapsedMilliseconds);             myStopWatch.Stop();         }     }     class Client     {         public static IEnumerable<Client> GetClients()         {             for (int i = 0; i < 100; i++)             {                 yield return new Client() { Id = Guid.NewGuid() };             }         }          public Guid Id { get; set; }          //This method has to be called before you use a client         //For the sample, I don't put it on the constructor         public async Task Initialize()         {             await Task.Factory.StartNew(() =>                                       {                                           Stopwatch timer = new Stopwatch();                                           timer.Start();                                           while(timer.ElapsedMilliseconds<1000)                                           {}                                           timer.Stop();                                        });             Console.WriteLine("Completed: " + Id);         }     } } 
like image 444
Ross Dargan Avatar asked Sep 24 '12 11:09

Ross Dargan


People also ask

How does the async keyword work in C sharp?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.

What is AsParallel in Linq C#?

AsParallel(IEnumerable) Enables parallelization of a query. AsParallel<TSource>(Partitioner<TSource>) Enables parallelization of a query, as sourced by a custom partitioner that is responsible for splitting the input sequence into partitions.

What does the await keyword do?

The await operator is used to wait for a Promise . It can only be used inside an async function within regular JavaScript code; however it can be used on its own with JavaScript modules.

What is the difference between Sync and await?

The differences between asynchronous and synchronous include: Async is multi-thread, which means operations or programs can run in parallel. Sync is single-thread, so only one operation or program will run at a time. Async is non-blocking, which means it will send multiple requests to a server.


2 Answers

There should be very little discernible difference.

In your first case:

var tasks = Client.GetClients().Select(async p => await p.Initialize()); 

The executing thread will (one at a time) start executing Initialize for each element in the client list. Initialize immediately queues a method to the thread pool and returns an uncompleted Task.

In your second case:

var tasks = Client.GetClients().AsParallel().Select(async p => await p.Initialize()); 

The executing thread will fork to the thread pool and (in parallel) start executing Initialize for each element in the client list. Initialize has the same behavior: it immediately queues a method to the thread pool and returns.

The two timings are nearly identical because you're only parallelizing a small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task.

If Initialize did some longer (synchronous) work before its first await, it may make sense to use AsParallel.

Remember, all async methods (and lambdas) start out being executed synchronously (see the official FAQ or my own intro post).

like image 150
Stephen Cleary Avatar answered Nov 02 '22 18:11

Stephen Cleary


There's a singular major difference.

In the following code, you are taking it upon yourself to perform the partitioning. In other words, you're creating one Task object per item from the IEnumerable<T> that is returned from the call to GetClients():

var tasks= Client.GetClients().Select(async p => await p.Initialize()); 

In the second, the call to AsParallel is internally going to use Task instances to execute partitions of the IEnumerable<T> and you're going to have the initial Task that is returned from the lambda async p => await p.Initialize():

var tasks = Client.GetClients().AsParallel().     Select(async p => await p.Initialize()); 

Finally, you're not really doing anything by using async/await here. Granted, the compiler might optimize this out, but you're just waiting on a method that returns a Task and then returning a continuation that does nothing back through the lambda. That said, since the call to Initialize is already returning a Task, it's best to keep it simple and just do:

var tasks = Client.GetClients().Select(p => p.Initialize()); 

Which will return the sequence of Task instances for you.

like image 41
casperOne Avatar answered Nov 02 '22 19:11

casperOne