While using asynchronous programming you might come across different scenarios. A few of those are explained here briefly.
Awaiting a task in Non Blocking manner
For this you just have to await the async method that you want to run in non blocking manner.public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { Task t = Task.Run(() => { long sum = 0; int n = 5000000; for (int i = 1; i <= n; i++) { sum += i; } Console.WriteLine("Sum is : {0}", sum); }); await t; Console.WriteLine("Task completed"); }
The output of above code on calling Execute() is:-After calling ExecuteAsync
Sum is : 12500002500000
Task completed
Awaiting a task in Blocking manner
While using async & await you might come across situation where you don't want to call an async method asynchronously, that is you want to wait for the task to complete before proceeding to further execution. In that case you can either use Task.Wait method or Task.Result property. Each of these are explained below:-
- Task.Wait : It makes the calling thread to wait until the task is complete, that is it blocks further execution on the calling thread until the task is completed. It has other overloads as well in which you can specify the time duration for which the calling thread waits for the asynchronous operation to complete.
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { Task t = Task.Run(() => { long sum = 0; int n = 5000000; for (int i = 1; i <= n; i++) { sum += i; } Console.WriteLine("Sum is : {0}", sum); }); t.Wait(); Console.WriteLine("Task completed"); }
The output of above code on calling Execute() is:-
Sum is : 12500002500000
Task completed
After calling ExecuteAsync - Task.Result : It can only be used with Task<TResult>. It is mainly used to get the result value of a task but getting the value using Task<TResult>.Result property blocks the calling thread until the task is complete which is same as calling the Task.Wait method.
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { Task<long> t = Task.Run(() => { long sum = 0; int n = 5000000; for (int i = 1; i <= n; i++) { sum += i; } Console.WriteLine("Sum is : {0}", sum); return sum; }); var s = t.Result; Console.WriteLine("Task completed"); }
The output of above code on calling Execute() is:-
Sum is : 12500002500000This output is same as the output with calling the Wait method.
Task completed
After calling ExecuteAsync
- Task.Wait : It makes the calling thread to wait until the task is complete, that is it blocks further execution on the calling thread until the task is completed. It has other overloads as well in which you can specify the time duration for which the calling thread waits for the asynchronous operation to complete.
Delay the execution of a task
We can delay the operation of a task by a specified amount of time by using Task.Delay method. We can cause the time delay either at the beginning of a task or during the execution of a task. A typical example of delaying a task during execution is as shown below:-
public async Task ExecuteAsync() { //some code await Task.Delay(2000); //some code }
Wait for all of the specified tasks to complete
You might sometimes need to ensure that all of the specified tasks (more than one) are complete before proceeding further, in that case you can use await Task.WhenAll (non blocking) or Task.WaitAll (blocking). Both of them are demonstrated below:-
- Without using any of these methods, that is, without waiting for the tasks to complete :
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { Task t1 = Task.Run(async() = > { await Task.Delay(3000); Console.WriteLine("Task 't1' completed"); }); Task t2 = Task.Run(async() = > { await Task.Delay(1000); Console.WriteLine("Task 't2' completed"); }); Console.WriteLine("ExecuteAsync completed"); }
The output of above code on calling Execute() is:-
ExecuteAsync completed
After calling ExecuteAsync
Task 't2' completed
Task 't1' completed
- Using Task.WaitAll :
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { var tasks = new List<task>(); Task t1 = Task.Run(async () => { await Task.Delay(3000); Console.WriteLine("Task 't1' completed"); }); Task t2 = Task.Run(async () => { await Task.Delay(1000); Console.WriteLine("Task 't2' completed"); }); tasks.Add(t1); tasks.Add(t2); try { // Wait for both t1 and t2 to complete. Task.WaitAll(tasks.ToArray()); } catch (AggregateException e) { for (int j = 0; j < e.InnerExceptions.Count; j++) { Console.WriteLine("\n\n{0}", e.InnerExceptions[j].ToString()); } } Console.WriteLine("ExecuteAsync completed"); }
The output of above code on calling Execute() is:-
Task 't2' completed
Task 't1' completed
ExecuteAsync completed
After calling ExecuteAsync
- Using await Task.WhenAll :
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { var tasks = new List<task>(); Task t1 = Task.Run(async () => { await Task.Delay(3000); Console.WriteLine("Task 't1' completed"); }); Task t2 = Task.Run(async () => { await Task.Delay(1000); Console.WriteLine("Task 't2' completed"); }); tasks.Add(t1); tasks.Add(t2); try { await Task.WhenAll(tasks.ToArray()); } catch (AggregateException e) { for (int j = 0; j < e.InnerExceptions.Count; j++) { Console.WriteLine("\n\n{0}", e.InnerExceptions[j].ToString()); } } Console.WriteLine("ExecuteAsync completed"); }
The output of above code on calling Execute() is:-
After calling ExecuteAsync
Task 't2' completed
Task 't1' completed
ExecuteAsync completed
- Without using any of these methods, that is, without waiting for the tasks to complete :
Proceed if any one of the specified tasks completes
There might be situation where you want to proceed to further execution if any one of the specified task completes its operation. Like most of the cases mentioned above there are two ways of doing this as well. One is using Task.WaitAny (blocking) the other is await Task.WhenAny (non blocking). Taking the same example used above these two methods are demonstrated as:-
- Task.WaitAny :
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { var tasks = new List<task>(); Task t1 = Task.Run(async () => { await Task.Delay(3000); Console.WriteLine("Task 't1' completed"); }); Task t2 = Task.Run(async () => { await Task.Delay(1000); Console.WriteLine("Task 't2' completed"); }); tasks.Add(t1); tasks.Add(t2); try { Task.WaitAny(tasks.ToArray()); } catch (AggregateException e) { for (int j = 0; j < e.InnerExceptions.Count; j++) { Console.WriteLine("\n\n{0}", e.InnerExceptions[j].ToString()); } } Console.WriteLine("ExecuteAsync completed"); }
The output of above code on calling Execute() is:-
Task 't2' completed
ExecuteAsync completed
After calling ExecuteAsync
Task 't1' completed
- await Task.WhenAny :
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { var tasks = new List<task>(); Task t1 = Task.Run(async () => { await Task.Delay(3000); Console.WriteLine("Task 't1' completed"); }); Task t2 = Task.Run(async () => { await Task.Delay(1000); Console.WriteLine("Task 't2' completed"); }); tasks.Add(t1); tasks.Add(t2); try { await Task.WhenAny(tasks.ToArray()); } catch (AggregateException e) { for (int j = 0; j < e.InnerExceptions.Count; j++) { Console.WriteLine("\n\n{0}", e.InnerExceptions[j].ToString()); } } Console.WriteLine("ExecuteAsync completed"); }
The output of above code on calling Execute() is:-
After calling ExecuteAsync
Task 't2' completed
ExecuteAsync completed
Task 't1' completed
- Task.WaitAny :
-
Execute another task when a Task completes
If you want to execute another task when a task completes its execution then you can use the Task.ContinueWith method. A simple example is shown below :-
public void Execute() { ExecuteAsync(); Console.WriteLine("After calling ExecuteAsync"); Console.ReadKey(); } public async Task ExecuteAsync() { Task t1 = Task.Run(async () => { await Task.Delay(3000); Console.WriteLine("Task 't1' completed"); }); Task continuationTask = t1.ContinueWith(_ => { Console.WriteLine("Task 't2' completed"); }); await continuationTask; Console.WriteLine("ExecuteAsync completed"); }
The output of above code on calling Execute() is:-
After calling ExecuteAsync
Task 't1' completed
Task 't2' completed
ExecuteAsync completed
No comments:
Post a Comment