hhhhsdads
Table of Contents
Hi! As of a recent buzz around the community, after the introduction of the C# vNext in the world of .NET
languages, (more precisely on C# and VB.NET) its time to let you through and understand
how the features are working in current scenario. Well, it is true a large mass of people is writing about it but
believe me, I didn't saw any which gives you the full example under one shot. Hence, I thought I might
give it a try. In this post I will try to cover most of the bits related with Async programming model
and also to give you a chance to understand the concept and give feedback on the same.
SideNote : One of my article is in monthly survey, you would like this article too.It is also present here(another)
It had been a long way to go if I have to start talking about C# from the very beginning. But its
quite interesting if I give you the whole shot of entire evolution of C# as a language just now before
going into the latest C# adjustment. In
PDC 10,
Anders pointed out the entire evolution of C# language,
lets go into it first :
Basically C# is continuously getting enriched with newer concepts and hence gradually its becoming
the industry best language but it does include backward compatibility of each of the existing language
features. In the above figure, you can see, C# was introduced as a language way back in 2001 when it was
first introduced as truly Managed Code language. The initial C# language was great, but had lots of things
absent. Later on, C# 2.0 was introduced. It introduced with a great new feature Generics which was never
introduced before. C# 3.0 was actually for LINQ, a truly language integrated query syntax, where you can
dealt with querying your existing .NET data structures using simple lambdas or LINQ expressions without
manually traversing the list yourself. Finally its in .NET 4.0 the Task Parallel Library was introduced, which
lets you create more responsive applications by giving away Tasks for each ongoing operation.
If you have used Parallel Extensions to .NET, you might already know that Task was introduced to represent
the future. It represents an Ongoing operation that will result you an output in future. Task object has few
features which you might address :
- Task Scheduling
- Establish parent child relationship between Child task to its parent
- Implement cooperative cancellation
- Waits can be signaled without external wait handles
- Attach "continuation" task(s) using
ContinueWith
So task is the basic unit of Task Parallel Library which wraps up everything we need to invoke a Thread
and
allows to run a program module parallely.
C# 5.0 is introduced with one main motive in mind, that is to mold the language in such a way that the
programmer can program the logic as he would have done synchronously maintaining the original flow of
the program. C# already have Threads to deal with asynchronous kind of programming. With C# 2.0 it is very
easy to write Async style of programming where you can create a Delegate
and call its own implementation
of BeginInvoke
and EndInvoke
and put a callback in, which will be called as and when the execution is done.
But basically what happens, your code is getting more and more complex as you increasingly introduce more
and more asynchronous patterns. You need to have callbacks for each of those calls so that when the call
gets finished, the operation will finally invoke the callbacks and your rest of the logic gets executed.
Thereby, with greater extent of asynchrony in your code(which we often require) your code will look more
and more complex and hard to decipher for others. C# 5.0 keeps the notion of the programming model intact,
but lets you write your application just as you would have done for synchronous programming style with
the same logical flow and structure, but with few adjustments in your code and the work will work asynchronously.
So if you go on with the Asynchronous pattern, in terms of Parallelism, we call the new pattern
as Task Asynchronous Pattern. It is the first attempt to change the language a bit after Threads are
introduced in C# 1.0 to make it easier to write truly responsive applications. By Responsive
applications we mean, that we can leverage more work on one thread rather than blocking
threads for UI responsiveness.
Most of us has confusion in the concept of Asynchrony and concurrency. Well, I would say you think
differently than what you think now. Lets take the example of Parallelism. If you think of concurrency we are
thinking of dealing with CPU cycles. Say for instance, you want to do a big calculations for your application.
In such a situation, you want to do the calculation in parallel. So what you think? You need to have multiple
Threads running in parallel which finally gets you the output. Thus, if you think of a certain time in between
running of your application, you actually have more than one CPU busy with your calculation and makes maximum
utilization of the CPU, and concurrently accessing your resources. This is what we call Concurrency.
Asynchrony on the other hand, is a super set of Concurrency. So it includes concurrency as well as other
asynchronous calls which are not CPU bound. Lets say you are saving a big file in your hard drive, or you
want to download some data from the server. These things does share your CPU time-slices. But if you can
do this in asynchronous pattern, it will also be included in Asynchrony.
So to summarize, Asynchrony is a pattern which yields control instantly when called, but waits the callback
to arise later in future. Concurrency on the other hand, parallel execution of CPU bound applications.
Literally speaking, No... Its not. In present scenario, if you need to create a Responsive application
you always think of creating a new Thread from the ThreadPool, calling the Resource (which eventually
blocks the Thread for the moment) and finally get the result back when the device says he is ready. But
does it makes sense always? No. Say you are downloading a movie, which is Network bound. So basically
there is no involvement of CPU in this scenario. So according to Microsoft people, your UI Thread is actually
creating the Message and thows to the Network device to do this job and returns back immediately without
getting the result. The Network device will do its task accordingly (downloading the url) and finally find the
UI thread using SynchronizationContext
appropriately and return the result. Hence, when the Network
device finishes its work, it can communicate to the appropriate thread and invoke the callback. Isnt it sounds
good?
Yes, say you have 10 numbers of network calls to be made in parallel. In case of previous approach, you
would have created 10 Threads each of which will call the Network API and block itself until it gets the response.
Hence, even though you are not using a single time slice of CPU, all your ThreadPool
threads gets exhausted.
Well you might wonder, how about increasing the ThreadPool threads size? Well, you probably can, but this would
give additional pressure if all the network resources gets available after a while. Hence Async pattern can help you
in this regard. Such that, you would have called each of the resources asynchronousy from the same
thread, and wait for the Callback to arise.
Before I proceed what we have introduced, it is very interesting to know what is available now, so that you could
compare between the two approaches. Say you want to download few links from the server, as of now I am doing it
synchronously, I might use :
const string Feed = "http://www.codeproject.com/webservices/articlerss.aspx?cat={0}";
private void btnSync_Click(object sender, RoutedEventArgs e)
{
this.SynchronousCallServer();
}
public void SynchronousCallServer()
{
WebClient client = new WebClient();
StringBuilder builder = new StringBuilder();
for (int i = 2; i <= 10; i++)
{
this.tbStatus.Text = string.Format("Calling Server [{0}]..... ", i);
string currentCall = string.Format(Feed, i);
string rss = client.DownloadString(new Uri(currentCall));
builder.Append(rss);
}
MessageBox.Show(
string.Format("Downloaded Successfully!!! Total Size : {0} chars.",
builder.Length));
}
In the above method, I have called a WebServer Url directly using WebClient
and downloaded
the entire string which I later on append to the builder object and finally when all the links are
downloaded (sequentially) we show a MessageBox
to the user. You should also notice, we are also
updating a status message while downloading the urls. Now lets run our application and call the
method :
In the above figure you can see the application stops responding, as UI thread gets blocked when
the DownloadString
is called. You should also notice, the screed does not update itself with the
status message, as we can see only the final status message after all the strings gets downloaded.
Now this is not a good UI design. Is it ? I say no. So let us make it asynchronous to call the download
string sequentially as we are doing. So how different the code should look like:
const string Feed = "http://www.codeproject.com/webservices/articlerss.aspx?cat={0}";
private void btnaSyncPrev_Click(object sender, RoutedEventArgs e)
{
StringBuilder builder = new StringBuilder();
this.AsynchronousCallServerTraditional(builder, 2);
}
public void AsynchronousCallServerTraditional(StringBuilder builder, int i)
{
if (i > 10)
{
MessageBox.Show(
string.Format("Downloaded Successfully!!! Total Size : {0} chars.",
builder.Length));
return;
}
this.tbStatus.Text = string.Format("Calling Server [{0}]..... ", i);
WebClient client = new WebClient();
client.DownloadStringCompleted += (o,e) =>
{
builder.Append(e.Result);
this.AsynchronousCallServerTraditional(builder, i + 1);
};
string currentCall = string.Format(Feed, i);
client.DownloadStringAsync(new Uri(currentCall), null);
}
OMG! This is terrific. The code looks completely different. First of all the DownloadStringAsync
of WebClient
does not return the string, as the control is returned back immediately and hence
to get the Result we need to add an EventHandler
for DownloadStringCompleted
.
As the EventHandler
is actually a completely different method we need to send the StringBuilder
object
every time to the Callback method and eventually the callback recursively calls the same method
again and again to create the entire structure of data. So basically, asynchronous call to the same method
looks totally different.
Asynchronous pattern is been simplified like heaven with the introduction of C# vNext. As shown in the PDC 10
by Anders Hejlsberg here, introduces two new keywords "async" and "await" which totally simplifies
the asynchrony from the language perspective (You can also read my post
which I have posted just after PDC). Before we delve into these, let me take a look at the same code in this approach:
const string Feed = "http://www.codeproject.com/webservices/articlerss.aspx?cat={0}";
public async Task AsynchronousCallServerMordernAsync()
{
WebClient client = new WebClient();
StringBuilder builder = new StringBuilder();
for (int i = 2; i <= 10; i++)
{
this.tbStatus.Text = string.Format("Calling Server [{0}]..... ", i);
string currentCall = string.Format(Feed, i);
string rss = await client.DownloadStringTaskAsync(new Uri(currentCall));
builder.Append(rss);
}
MessageBox.Show(
string.Format("Downloaded Successfully!!! Total Size : {0} chars.",
builder.Length));
}
So the code looks identically the same with two keywords "async" and "await". Does it work? Yes, when you try
running the code, it works the same way as it would have done with synchronously. You have noticed that I have used
DownloadStringTaskAsync
, which actually an asynchronous implementation of DownloadString
with the same
approach. It is an extension method which will be available only if you install async CTP.
Asynchronous pattern is still in CTP, so you need to install few bits on your machine which will
update your Visual Studio 2010 to allow these two keywords.
- Visual Studio 2010 (No previous version supported). Try installing Express
- Visual Studio Async CTP
After you install both of them in your machine, reference AsyncCTPLibrary
which could be found
in %MyDocument%\Microsoft Visual Studio Async CTP\Samples\AsyncCtpLibrary.dll
to your application.
Following the PDC, we can saw async is a new modifier for a method, which lets the method to return
immediately after its been called. So when a method is called, the control is yielded immediately until
it finds the first await. So await is a contextual keyword which might be placed before any Task
(or any object
which implements GetAwaiter
) object which lets you to return the control back immediately while the
method gets executed. Once the method gets executed the caller finds the same block and invokes a GoTo
statement to the same position where we have left and registers the rest of the code as we wrote.
Each of those adjustments are made automatically from the compiler itself so no user intervention is required.
Well, compilers are good at State Machines. If you think of C# IEnumeramble
, the compiler actually
builds a State Machine internally for each yield statement you invoke. So when you write a logic which
corresponds to a method which has yield statement in it, the whole State Machine logic is prepared by
the compiler so that on a certain yield, it automatically determines the probable next yield based on the
work flow. C# asynchrony builds on top of the same approach. The compiler made appropriate modifications
to your program to build the complete state machine for the block. Hence, when you write await for a
block it actually yields the control after calling the method, and returns back a Task
object that represents the
ongoing method. If the ongoing method returns something it is returned as Task<T>
. Lets look at the figure
below:
The code runs in two phazes. First it calls AsynchronousCallServerMordern
method until it
finds an await, which returns a Task object immediately after registering the rest of the method in its State
Machine workflow step. But after it is returned to the caller, it again invokes an await, which returns the
control back to the UI (void return type in async
method means call and forget). Hence the UI will be available
immediately. After the call to DownloadStringTaskAsync
gets finished, one time slice is taken
by the program to run the existing code until it finds the next await, and it goes on until all of the links are downloaded
successfully. Finally the control is free for the UI totally.
While you think of this situation, you might be thinking how is it possible to return the control before executing the whole method instance. As I didnt told you the entire fact in this regard, this type of confusion might occur to you. Let me try to clarify this a bit more.
So, when you are creating an async method, you are actually creating a new instance of the method. Methods are generally to be run. But if you think of method in real time, its the instance which runs. .NET actually cretes a statemachine object which holds different steps of the method body. If you have already used up StateMachine, you must know, state machine can easily keep track of the current state of the flow. So the method instance is nothing but the instance of a state machine, which holds the parameters, local variables, the state of the method that it is currently is. Thus when you are going to encounter the await statement, it actually saves the satemachine object as a variable which it resumes again when the awaiter gets the response.
For instance, I write the code as below :
Console.WriteLine("Before await");
await TaskEx.Delay(1000);
Console.WriteLine("After await");
Now, when you compile the assembly, it actually creates an object of StateMachine with two Method (1 for each state).
- It takes the First delegate and associated it with
Console.WriteLine("Before await");
await TaskEx.Delay(1000);
Say for instance, it names it as State 1.
- It takes the rest of the part to a new method.
Console.WriteLine("After await");
So basically there is no single method body here, but the compiler creates 2 method(I will clarify those in detail just after I define TaskAwaiter
) of which the first one is called first, and the object stores the current state as State1, and after a wait, when the Task Placeholder gets the appropriate result, it invokes the Next State and gives its completion.
How wonder, Exception Handling works the same as synchronous calls as we do for asynchronous. Prevously
while dealing with async code, say for instance for WebClient.DownloadStringAsync
we need
to manually check for every DownloadComplete
calls if e.Error
has any value or not. But
in case of async pattern, you can use your very own Try/Catch block to wrap around your async code
and the error will be thrown automatically to catch in the block. So if you want to put the exception
handling for the code you would write :
public async Task AsynchronousCallServerMordernAsync()
{
WebClient client = new WebClient();
StringBuilder builder = new StringBuilder();
for (int i = 2; i <= 10; i++)
{
try
{
this.tbStatus.Text = string.Format("Calling Server [{0}]..... ", i);
string currentCall = string.Format(Feed, i);
string rss = await client.DownloadStringTaskAsync(new Uri(currentCall));
builder.Append(rss);
}
catch(Exception ex) {
this.tbStatus.Text =
string.Format("Error Occurred -- {0} for call :{1}, Trying next",
ex.Message, i);
}
MessageBox.Show(
string.Format("Downloaded Successfully!!! Total Size : {0} chars.",
builder.Length));
}
Cool. Yes it is. The async pattern does not need to do any modification to work with exceptions.
As everything is done, you might be thinking is it not possible to invoke each of the statement parallely
rather than sequentially, so that we could save some time. Yes, you are right. It is absolutely possible to
deal with multiple tasks all at once and later on await for all at a time. To do this, let me modify the code :
private async void btnaSyncPresParallel_Click(object sender, RoutedEventArgs e)
{
await this.AsynchronousCallServerMordernParallelAsync();
}
public async Task AsynchronousCallServerMordernParallelAsync()
{
List> lstTasks = new List>();
StringBuilder builder = new StringBuilder();
for (int i = 2; i <= 10; i++)
{
using (WebClient client = new WebClient())
{
try
{
this.tbStatus.Text = string.Format("Calling Server [{0}]..... ", i);
string currentCall = string.Format(Feed, i);
Task task = client.DownloadStringTaskAsync(new Uri(currentCall));
lstTasks.Add(task);
}
catch (Exception ex)
{
this.tbStatus.Text =
string.Format("Error Occurred -- {0} for call :{1}, Trying next",
ex.Message, i);
}
}
}
try
{
string[] rss = await TaskEx.WhenAll(lstTasks);
foreach(string s in rss)
builder.Append(s);
}
catch {}
MessageBox.Show(
string.Format("Downloaded Successfully!!! Total Size : {0} chars.",
builder.Length));
}
So basically, what we need to do, is to create the object of WebClient inside the loop, and also
need to remove the await for the DownloadStringTaskAsync
call. As I have already told you that await
immediately returns the control back to the caller, we do not need it to return immediately. Rather we create
a list of all the Tasks and finally aggregate all the tasks into one using TaskEx.WhenAll
and invoke
await on that. Hence the TaskEx.WhenAll
will return you an array of strings, which you might use when
all the tasks finishes. OMG, the call to it is returned immediately.
Another important part of the code is to cancel the existing ongoing task. For that, async pattern introduces
a new object called CancellationTokenSource
. You can make use of it to cancel an existing
operation that is going on. Lets take a look at the sample application to demonstrate the cancellation.
In this application, we have two Buttons, one of which calls Codeproject RSS feed, while the cancel button
invokes the cancellation for the operation. Lets take a quick pick, how I build the application.
string url = "http://www.codeproject.com/WebServices/ArticleRSS.aspx";
CancellationTokenSource cancelToken;
private async void btnSearch_Click(object sender, RoutedEventArgs e)
{
var result = await LoadArticleAsync();
this.LoadArticleList(result);
await TaskEx.Delay(5000);
if (cancelToken != null)
{
cancelToken.Cancel();
tbstatus.Text = "Timeout";
}
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
if (cancelToken != null)
{
cancelToken.Cancel();
tbstatus.Text = "Cancelled";
}
}
void LoadArticleList(string result)
{
var articles = from article in XDocument.Parse(result).Descendants("item")
let subject = article.Element("subject").Value
let title = article.Element("title").Value
let description = article.Element("description").Value
let url = article.Element("link").Value
let author = article.Element("author").Value
let publishdate = article.Element("pubDate").Value
select new Article
{
Subject = subject,
Title = title,
Description = description,
PublishDate = publishdate,
Author = author,
Url = url
};
ICollectionView icv = CollectionViewSource.GetDefaultView(articles);
icv.GroupDescriptions.Add(new PropertyGroupDescription("Subject"));
this.lstArticles.DataContext = icv;
}
async Task LoadArticleAsync()
{
cancelToken = new CancellationTokenSource();
tbstatus.Text = "";
try
{
tbstatus.Text = "Searching... ";
var client = new WebClient();
var taskRequest = await client.DownloadStringTaskAsync(this.url);
tbstatus.Text = "Task Finished ... ";
return taskRequest;
}
catch (TaskCanceledException)
{
return null;
}
finally
{
cancelToken = null;
}
}
So basically, I have used a WPF application (To simplify I didn't used MVVM) where I have invoked
a web DownloadStringTaskAsync
call. The only thing that you need to do for TaskCancellation
is to create the instance of CancellationTokenSource
inside the block which you want to cancel.
In the above code, I have created the object inside the method LoadArticleAsync
, hence
whenever I invoke cancelToken.Cancel
, the await
for this call will be released. You can even do calls like
cancelToken.CancelAfter(2000)
to cancel the operation after 2 seconds.
Last but not the least, what if, you really want to use a new Thread
to call your method? With async
pattern, it is even easier to do than ever before. Just take a look at the code :
private async void btnGoCPUBound_Click(object sender, RoutedEventArgs e)
{
await new SynchronizationContext().SwitchTo();
long result = this.DoCpuIntensiveWork();
await Application.Current.Dispatcher.SwitchTo();
MessageBox.Show(string.Format("Largest Prime number : {0}", result));
}
public long DoCpuIntensiveWork()
{
long i = 2, j, rem, result = 0;
while (i <= long.MaxValue)
{
for (j = 2; j < i; j++)
{
rem = i % j;
if (rem == 0)
break;
}
if (i == j)
result = i;
i++;
}
return result;
}
In the above case we use SynchronizationContext.SwitchTo
to get a YieldAwaitable
which creates a new
thread from the ThreadPool
and returns an object that implements GetAwaitable
. Hence you can await
on the same. Later on, you can use your Dispatcher.SwitchTo
to return back to the original thread again.
So isn't it easy enough? Yes really, its now fun switching from one thread to another.
There are quite a few things to remember in this regard, lets list them :
- For any
async
block it is important to have at least one await
, otherwise the whole block will work
synchronously.
- Any
async
method should postfix Async (as a rule), so your method name should look like
MyMethodAsync
which you put an async
keyword before it.
- Any async method can return void(call and forget),
Task
or Task<T>
based on the Result
the
await method sends.
- The compiler does the adjustment to find the same caller and invokes
GoTo
statement to execute
the rest of the logic from the same position where await is invoked, rather than doing a Callback.
- Everything is managed by a State Machine Workflow by the compiler
- CPU bound calls can have its own thread, but async method does not create a new Thread by itself
and blocking it waiting for the caller to arrive. Network or I/O bound calls do not involve any new Thread
to be created under the hood
- Any object which needs to await must have
GetAwaiter
(even extension method) associated with it.
This is basically what you must know to deal with async pattern. In later section, I will try to go
more deeper aspect of the async framework.
Well, it is always good to go deeper into what exactly happening with this. To check, I have used Reflector
and found few interesting facts:
As I have already told you, await works only for objects which implements GetAwaiter
. Now Task has the method GetAwaiter
, which returns another object (called TaskAwaiter
)
which is used to actually register the await pattern. Any awaiter object should include basic methods like
BeginAwait
and EndAwait
. There are quite a number of methods implemented
into the library which is awaitable. Now if you look into the BeginAwait
and EndAwait
,
its basically creating some delegates similar to what you might do in case of normal asynchronous pattern.
The BeginAwait actually calls TrySetContinuationforAwait
, whic actually breaks apart the existing method body into two
separate blocks and registers the next part of each await statement to the continuation of the Task,
just like you are doing like
Task1.ContinueWith(Task2);
where Task2 represents the Rest of the code to run in callback. So if you want your object to work
with asynchronous patter, you must have GetAwaiter
implemented which returns an object BeginAwait
and
EndAwait
defined. As of surprise, extension methods can also be used for writing the same for now, I am
eager to see if it is possible in original version.
As in the previous section, I showed how to build an awaiter, but lets look into how our own application
looks like after compiler does the trick
To demonstrate this, let me create one of the most simplest application with single await and try
to demonstrate the IL of it. Lets look into the code :
public class AsyncCaller
{
public async void GetTaskAsync(List tasks)
{
await TaskEx.WhenAny(tasks);
}
}
So, I created one class library and added this method to it. It basically awaits for any task to complete
from the list of Tasks. Now if you look inside the assembly, it would look :
public void GetTaskAsync(List tasks)
{
d__0 d__ = new d__0(0);
d__.<>4__this = this;
d__.tasks = tasks;
d__.MoveNextDelegate = new Action(d__.MoveNext);
d__.$builder = VoidAsyncMethodBuilder.Create();
d__.MoveNext();
}
There is a compiler generated type which separates the two parts of the code into two tasks
and allows it to continue with the other method which is created using
VoidAsyncMethodBuilder.Create
after
WhenAll
retruns back the output.
[CompilerGenerated]
private sealed class <GetTaskAsync>d__0
{
private bool $__disposing;
private bool $__doFinallyBodies;
public VoidAsyncMethodBuilder $builder;
private int <>1__state;
public List<Task> <>3__tasks;
public AsyncCaller <>4__this;
private Task <1>t__$await1;
private TaskAwaiter<Task> <a1>t__$await2;
public Action MoveNextDelegate;
public List<Task> tasks;
[DebuggerHidden]
public <GetTaskAsync>d__0(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
public void Dispose()
{
this.$__disposing = true;
this.MoveNext();
this.<>1__state = -1;
}
public void MoveNext()
{
try
{
this.$__doFinallyBodies = true;
if (this.<>1__state != 1)
{
if (this.<>1__state == -1)
{
return;
}
this.<a1>t__$await2 = TaskEx.WhenAny(this.tasks).GetAwaiter<Task>();
this.<>1__state = 1;
this.$__doFinallyBodies = false;
if (this.<a1>t__$await2.BeginAwait(this.MoveNextDelegate))
{
return;
}
this.$__doFinallyBodies = true;
}
this.<>1__state = 0;
this.<1>t__$await1 = this.<a1>t__$await2.EndAwait();
Task task1 = this.<1>t__$await1;
this.<>1__state = -1;
this.$builder.SetCompleted();
}
catch (Exception)
{
this.<>1__state = -1;
this.$builder.SetCompleted();
throw;
}
}
Yes the CompilerGenerated
nested type creates the necessary adjustment to hide the original call to BeginAwait
. If you see MoveNext
, you can definitely get the idea that TaskEx.WhenAny
is called from there which gets the Awaiter. The Awaiter is then registered to MoveNextDelegate which stores the continuation part of the program. Once the MoveNext
finished its task it notifies using builder.SetCompleted
which eventually try to call the probable next delegate (which isn't there).
Now as you know that methods are not run the way we think of normally
in case of
async
, it actually creates a StateMachine object.The
VoidAsyncMethodBuilder.Create
actually returns the object of the StateMachine, which internally holds each state of the method in the compiler generated sealed class. The annonymous type created holds each method into public properties, as for me
d__.MoveNextDelegate
is set before calling the
TaskAwaiter.BeginAwait
.
Thus the main thing is, when we are initially calling the method, we are actually calling the first part of the method, and after it calls
BeginAwait
, it eventually save the whole object in the context as a statemachine and return the control. Now when the Task has the result, it automatically invokes the
EndAwaiter
from itself, and the Object is again taken into account, it sees what state the object is now, and calls MoveNext accordingly(which eventually calls the next part of the method).
You should note, these kind of creating large computer generated Type will not take place in final release, but I just showed this
to demonstrate the concept and also for better understanding. I would also recommend you to look into
it to learn more about it.
Nothing much so far for Debugging, but still there is a class named DebugInfo
inside System.Runtime.CompilerServices.AsyncMethodBuilder
. Though the class is internal but yet you can invoke the static method ActiveMethods
to get few data available for debugging such as the methods which are not yet finished, or more precisely the methods which have intermediate statemachine available in the context will be listed here.
The ActiveMethod is actually returns a List<DebugInfo>
which lists :
- StartDateTime
- StartingThread
- StartingExecutionContext
- Task
When any Task is awaited, every time it builds a State Machine object which holds each step of the method body. During the initilization phaze of this, the AsyncMethodBuilder is called. In the constructor, the DebugInfo was created. If you see in reflector you will see :
The AsyncMethodBuilder
actually adds the Task
object to create a DebugInfo
inside it, which is then removed when the Task completes.
The DebugInfo
actually lists only ActiveMethods while others are not browsable from Debugger.
This is basically in very priliminary stage, so I think it will add few more in later builds of Async framework.
To see those information, you can add the variable in Watch window of Visual studio and have a quick pick on those. For more details you can browse my blog post on this.
- Initial Draft : 14th November 2010
- 2nd Edition : Fixed image issue, and few spelling mistakes.
- 3rd Edition : As few people told me to clarify some sections more, I made those adjustments.
- 4th Edition: Added Debug capabilities to Async
After the introduction of new Async pattern, I was thinking to learn the same by trying a few
applications myself. I did everything just for fun. If I do any mistake please let me know about it. Also
do give your feedback on this new pattern.
Thank you for reading