The await expression specifies a task to be done asynchronously.
Syntax:
await task
There are now a number of BCL methods that return objects of type Task<T>, you’ll most likely have your own methods that you want to use as the task for an await expression. The easiest way to do that is to create a Task from your method using the Task.Run method.
the most important fact about the Task.The run method is that it runs your method on a different thread.
One signature of the Task.Run method is,it takes a Func delegate as a parameter.
Task Run( Func<TReturn> func
So, to pass your method to the Task.Run method, you need to create a delegate from it.
There are three ways to do this.
In the code, method Get20 has a form compatible with a Func<int> delegate since it takes no parameters and returns an int.
- In the first instance, which is in the first two lines of method DoWorkAsync, a Func delegate named twenty is created using Get20. That delegate is then used in the Task.Run method in the next line.
- In the second instance, a Func delegate is created right in the Task.Run method’s parameter list.
- The last instance doesn’t use the Get20 method at all. It uses the return statement that comprises the body of the Get20 method, and uses it as the body of a lambda expression compatible with a Func<int> delegate. The lambda expression is implicitly converted to the delegate.
class MyClass
{
public int Get20() // Func<int> compatible
{
return 20;
}
public async Task DoWorkAsync()
{
Func<int> twenty = new Func<int>(Get20);
int a = await Task.Run(twenty);
int b = await Task.Run(new Func<int>(Get20));
int c = await Task.Run(() => { return 20; });
Console.WriteLine("{0} {1} {2}", a, b, c);
}
class Program
{
static void Main()
{
Task t = (new MyClass()).DoWorkAsync();
t.Wait();
}
}
}
Exception Handling and the await Expression:
You can use await expression inside a try statement.
You can use await expression inside a try statement.
class Program
{
static void Main(string[] args)
{
Task t = BadAsync();
t.Wait();
Console.WriteLine("Task Status : {0}", t.Status);
Console.WriteLine("Task IsFaulted: {0}", t.IsFaulted);
}
static async Task BadAsync()
{
try
{
await Task.Run(() => { throw new Exception(); });
}
catch
{
Console.WriteLine("Exception in BadAsync");
}
}
}
Cancelling an async Operation :
You can cancel your own async operation.There are two classes in the System.Threading.Tasks namespace that are designed for this purpose: Cancellation Token and CancellationTokenSource.
- A Cancellation Token object contains the information about whether a task should be canceled or not.
- A task that has a CancellationToken object needs to periodically inspect it to see what the token’s state is. If the CancellationToken object’s
Is Cancellation Requested property is set to true, the task should halt its operations and return. - A Cancellation Token is nonreversible and can only be used once. That is, once it’s IsCancellationRequested property is set to true, it can’t be changed.
- A CancellationTokenSource object creates a CancellationToken object, which can then be given to various tasks. Any objects holding a cancellationTokenSource can call its Cancel method, which sets the CancellationToken’s IsCancellationRequested property to true.
class Program
{
static void Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
MyClass mc = new MyClass();
Task t = mc.RunAsync(token);
//Thread.Sleep( 3000 ); // Wait 3 seconds.
//cts.Cancel(); //cancel the operation.
t.Wait();
Console.WriteLine("Was Cancelled: {0}", token.IsCancellationRequested);
}
}
class MyClass
{
public async Task RunAsync(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return;
await Task.Run(() => CycleMethod(ct), ct);
}
void CycleMethod(CancellationToken ct)
{
Console.WriteLine("Starting CycleMethod");
const int max = 5;
for (int i = 0; i < max; i++)
{
if (ct.IsCancellationRequested) // Monitor the CancellationToken.
return;
Thread.Sleep(1000);
Console.WriteLine(" {0} of {1} iterations completed", i + 1, max);
}
}
}
Output:
Starting CycleMethod
1 of 5 iterations completed
2 of 5 iterations completed
3 of 5 iterations completed
4 of 5 iterations completed
5 of 5 iterations completed
Was Cancelled: False
If you uncomment the Thread.Sleep and Cancel statements in method Main, the task is canceled after three seconds and below is the output:
await taskStarting CycleMethod 1 of 5 iterations completed2 of 5 iterations completed3 of 5 iterations completedWas Cancelled: True
In your async method, if you want to wait on Tasks as your await expression. This allows your async method to return to the calling method, but allows the async method to wait for completion of one or all of a set of tasks. The calls that allow this are the Task.WhenAll and Task.WhenAny methods.
Output:
class MyDownloadString
{
public void DoRun()
{
Task<int> t = CountCharactersAsync("http://www.csharpstar.com", "http://www.techkatak.com");
Console.WriteLine("DoRun: Task {0}Finished", t.IsCompleted ? "" : "Not ");
Console.WriteLine("DoRun: Result = {0}", t.Result);
}
private async Task<int> CountCharactersAsync(string site1, string site2)
{
WebClient wc1 = new WebClient();
WebClient wc2 = new WebClient();
Task<string> t1 = wc1.DownloadStringTaskAsync(new Uri(site1));
Task<string> t2 = wc2.DownloadStringTaskAsync(new Uri(site2));
List<Task<string>> tasks = new List<Task<string>>();
tasks.Add(t1);
tasks.Add(t2);
await Task.WhenAll(tasks);
Console.WriteLine(" CCA: T1 {0}Finished", t1.IsCompleted ? "" : "Not ");
Console.WriteLine(" CCA: T2 {0}Finished", t2.IsCompleted ? "" : "Not ");
return t1.IsCompleted ? t1.Result.Length : t2.Result.Length;
}
}
class Program
{
static void Main()
{
MyDownloadString ds = new MyDownloadString();
ds.DoRun();
}
}
DoRun: Task Not Finished
CCA: T1 Finished
CCA: T2 Finished
DoRun: Result = 105212