In this lesson, I want to talk about the keywords we've added to several spots in our
source code. The keywords I'm referring to are:
1. async
2. await
3. Task<T>
You see all three of them in the GetFlickrImages() method:
These keywords are newly added to C# 5.0 and are generally referred to as the new
"async"—short for "asynchronous" or "asynchrony"—feature. In a nut shell, this new
feature is a simplified way of improving the performance of the app and making it more
responsive to the user without the complexity of writing code to use multiple threads. If
you call a method of the Windows Phone API or some other library supporting async
that could potentially take a "long time", the method will say, "I promise to get those
results to you as soon as possible, so go on about your business and I'll let you know
when I'm done". The app can then continue executing, and can even exit out of method
contexts. Another word for this in computer programming terminology is a "promise".
Under the hood, when you compile this source code, the Compiler picks apart the
source code and implements a complex series of statements in the Intermediate
Language to allow this to happen flawlessly and it does it without the use of multiple
threads in most cases.
Async is best used for operations that have a high degree of latency, but are not compute intensive. So, for example, we want to retrieve data from a Web API like we're doing in the GetFlickrImages() method. Before async, our app would block the execution of code waiting for Flickr's web service to reply with the data we requested. That could take a second, or two, or three, which is an eternity in computing. But the Phone's PROCESSOR is not busy at all. It's just sitting there, waiting for a reply from the Flickr web service.
This is known as "I/O Bound" ... I/O means "In / Out" ... so things like the file system, the network, the camera, etc., involve "I/O bound operations" and are good candidates for async. In fact, the Windows Phone API designers decided to bake async into all I/O Bound operations, forcing you to use this to keep the phone
responsive to the end user.
Contrast that to a compute-intensive operation such as a photo filter app that must take
a large image from the camera and run complex mathematical algorithms to change the
colors or the position of each pixel in the image. That could take a long time, too, but in
that case, the Phone's processor is hard at work. This type of operation is known as
"CPU Bound". This is NOT a good use of async. In this case, you would want to
consider a Background Worker which helps to manage threads on the Windows Phone
platform. If you are developing in .NET, you may prefer to work with threading via the
Task Parallel Library instead, or revert back to managing threads manually, which has
been an option since the very earliest versions of .NET.
Understanding multi-threading, parallel programming, the Task Parallel Library, even
Background Workers on the Windows Phone API are WAY beyond the scope of this
series and this lesson. It's a large topic and I'll not lie to you—it makes my head spin. If
you want to learn a little more about async and how it applies to the Windows RunTime,
check out:
Working with Async Methods in the Windows Runtime
... and be sure to read the comments where I further explain this idea.
But back to the topic at hand ... async is for those common occasions when you have a
blocking operation that is not compute intensive, such as our case here where we are
waiting for the HttpClient.GetStringAsync() operation to complete. In this case, we use
the await keyword, which says, "I'll get back to you when I'm finished". The thread of
execution can continue on through the other lines of code until it absolutely must have
the results of that operation. Now, in our case, we attempt to call
JsonConvert.DeserializeObject<FlickrData> in the very next line of code, so little
advantage is gained. However, we must still use the await keyword because the
HttpClient.GetStringAsync() method returns a Task<T>. That method requires we await.
You'll see await-able methods with a common convention ... they all end with the suffix
Async.
Furthermore, any method that uses an await-able method must be marked with the
async keyword in their method signature, AND if it is supposed to return a value it mustreturn the value wrapped with a Task<T>. If the method is void, it will merely be marked void in the method signature. Since the HttpClient.GetStringAsync() is marked with await, and our method returns a List<FlickrImage> we must mark our method with
async and wrap the List<FlickrImage> with a Task<T>. That essentially means that any
method that calls our method can continue executing until it absolutely needs that
List<FlickrImage>.
Therefore, take a look at the method that calls our FlickrImage.GetFlickrImages()
method:
That's why in line 37 (above) we must use the await keyword—our
FlickrImage.GetFlickrImages() was forced to be await-able (since it used the
HttpClient.GetStringAsync()). Notice that we also had to modify the event handler
method's method signature adding the async keyword. Since this is what they refer to
as a "top level method", the chain of adding async stops here.
Again, remind me, why are we doing all of this? In hopes of making our app more
responsive. This operation should not be blocking the Phone's processor from taking on other tasks like answering a phone call or running background tasks on behalf of other apps. It won't prevent the user from selecting any of the hardware buttons on the phone and getting an instant response.
Recap
To recap, the big take away in this lesson is what async is, how it works, the scenarios it was designed to address, and it's overall purpose—to keep the phone and your apps
responsive during long running I/O bound operations.
No comments:
Post a Comment