diff --git a/docs/async/async-in-depth.md b/docs/async/async-in-depth.md new file mode 100644 index 0000000000000..df416e83a0017 --- /dev/null +++ b/docs/async/async-in-depth.md @@ -0,0 +1,132 @@ +# Async In Depth + +By [Phillip Carter](https://github.com/cartermp) + +Writing I/O- and CPU-bound asynchronous code is straightforward using the .NET Task-based async model. The model is exposed by the `Task` and `Task` types and the `async` and `await` language keywords. This article explains how to use .NET async and provides insight into the async framework used under the covers. + +## Task and Task<T> + +Tasks are constructs used to implement what is known as the [Promise Model of Concurrency](https://en.wikipedia.org/wiki/Futures_and_promises). In short, they offer you a "promise" that work will be completed at a later point, letting you coordinate with the promise with a clean API. + +* `Task` represents a single operation which does not return a value. +* `Task` represents a single operation which returns a value of type `T`. + +It’s important to reason about tasks as abstractions of work happening asynchronously, and *not* an abstraction over threading. By default, tasks execute on the current thread and delegate work to the Operating System, as appropriate. Optionally, tasks can be be explicitly requested to run on a separate thread via the `Task.Run` API. + +Tasks expose an API protocol for monitoring, waiting upon and accessing the result value (in the case of `Task`) of a task. Language integration, with the `await` keyword, provides a higher-level abstraction for using tasks. + +Using `await` allows your application or service to perform useful work while a task is running by yielding control to its caller until the task is done. Your code does not need to rely on callbacks or events to continue execution after the task has been completed. The language and task API integration does that for you. If you’re using `Task`, the `await` keyword will additionally “unwrap” the value returned when the Task is complete. The details of how this works are explained further below. + +You can learn more about tasks and the different ways to interact with them in the [Task-based Asynchronous Pattern (TAP) Article](https://msdn.microsoft.com/en-us/library/hh873175(v=vs.110).aspx). + +## Deeper Dive into Tasks for an I/O-Bound Operation + +The following section describes a 10,000 foot view of what happens with a typical async I/O call. Let's start with a couple examples. + +The first example calls an async method and returns an active task, likely yet to complete. + +```csharp +public Task GetHtmlAsync() +{ + // Execution is synchronous here + var client = new HttpClient(); + + return client.GetStringAsync("http://www.dotnetfoundation.org"); +} +``` + +The second example adds the use of he `async` and `await` keywords to operate on the task. + +```csharp +public async Task GetFirstCharactersCountAsync(string url, int count) +{ + // Execution is synchronous here + var client = new HttpClient(); + + // Execution of GetFirstCharactersCountAsync() is yielded to the caller here + // GetStringAsync returns a Task, which is *awaited* + var page = await client.GetStringAsync("http://www.dotnetfoundation.org"); + + // Execution resumes when the client.GetStringAsync task completes, + // becoming synchronous again. + + if (count > page.Length) + { + return page; + } + else + { + return page.Substring(0, count); + } +} +``` + +The call to `GetStringAsync()` calls through lower-level .NET libraries (perhaps calling other async methods) until it reaches a P/Invoke interop call into a native networking library. The native library may subsequently call into a System API call (such as `write()` to a socket on Linux). A task object will be created at the native/managed boundary, possibly using [TaskCompletionSource](https://msdn.microsoft.com/en-us/library/dd449202(v=vs.110).aspx). The task object will be passed up through the layers, possibly operated on or directly returned, eventually returned to the initial caller. + +In the second example above, a `Task` object will be returned from `GetStringAsync`. The use of the `await` keyword causes the method to return a newly created task object. Control returns to the caller from this location in the `GetFirstCharactersCountAsync` method. The methods and properties of the [Task](https://dotnet.github.io/api/System.Threading.Tasks.Task%601) object enable callers to monitor the progress of the task, which will complete when the remaining code in GetFirstCharactersCountAsync has executed. + +After the System API call, the request is now in kernel space, making its way to the networking subsystem of the OS (such as `/net` in the Linux Kernel). Here the OS will handle the networking request *asynchronously*. Details may be different depending on the OS used (the device driver call may be scheduled as a signal sent back to the runtime, or a device driver call may be made and *then* a signal sent back), but eventually the runtime will be informed that the networking request is in progress. At this time, the work for the device driver will either be scheduled, in-progress, or already finished (the request is already out "over the wire") - but because this is all happening asynchronously, the device driver is able to immediately handle something else! + +For example, in Windows an OS thread makes a call to the network device driver and asks it to perform the networking operation via an Interrupt Request Packet (IRP) which represents the operation. The device driver recieves the IRP, makes the call to the network, marks the IRP as "pending", and returns back to the OS. Because the OS thread now knows that the IRP is "pending", it doesn't have any more work to do for this job and "returns" back so that it can be used to perform other work. + +When the request is fulfilled and data comes back through the device driver, it notifies the CPU of new data received via an interrupt. How this interrupt gets handled will vary depending on the OS, but eventually the data will be passed through the OS until it reaches a system interop call (for example, in Linux an interrupt handler will schedule the bottom half of the IRQ to pass the data up through the OS asynchronously). Note that this *also* happens asynchronously! The result is queued up until the next available thread is able execute the async method and "unwrap" the result of the completed task. + +Throughout this entire process, a key takeaway is that **no thread is dedicated to running the task**. Although work is executed in some context (i.e. the OS does have to pass data to a device driver and respond to an interrupt), there is no thread dedicated to *waiting* for data from the request to come back. This allows the system to handle a much larger volume of work rather than waiting for some I/O call to finish. + +Although the above may seem like a lot of work to be done, when measured in terms of wall clock time, it’s miniscule compared to the time it takes to do the actual I/O work. Although not at all precise, a potential timeline for such a call would look like this: + +0-1————————————————————————————————————————————————–2-3 + +* Time spent from points `0` to `1` is everything up until an async method yields control to its caller. +* Time spent from points `1` to `2` is the time spent on I/O, with no CPU cost. +* Finally, time spent from points `2` to `3` is passing control back (and potentially a value) to the async method, at which point it is executing again. + +### What does this mean for a server scenario? + +This model works well with a typical server scenario workload. Because there are no threads dedicated to blocking on unfinished tasks, the server threadpool can service a much higher volume of web requests. + +Consider two servers: one that runs async code, and one that does not. For the purpose of this example, each server only has 5 threads available to service requests. Note that these numbers are imaginarily small and serve only in a demonstrative context. + +Assume both servers receive 6 concurrent requests. Each request performs an I/O operation. The server *without* async code has to queue up the 6th request until one of the 5 threads have finished the I/O-bound work and written a response. At the point that the 20th request comes in, the server might start to slow down, because the queue is getting too long. + +The server *with* async code running on it still queues up the 6th request, but because it uses `async` and `await`, each of its threads are freed up when the I/O-bound work starts, rather than when it finishes. By the time the 20th request comes in, the queue for incoming requests will be far smaller (if it has anything in it at all), and the server won't slow down. + +Although this is a contrived example, it works in a very similar fashion in the real world. In fact, you can expect a server to be able to handle an order of magnitude more requests using `async` and `await` than if it were dedicating a thread for each request it receives. + +### What does this mean for client scenario? + +The biggest gain for using `async` and `await` for a client app is an increase in responsiveness. Although you can make an app responsive by spawning threads manually, the act of spawning a thread is an expensive operation relative to just using `async` and `await`. Especially for something like a mobile game, impacting the UI thread as little as possible where I/O is concerned is crucial. + +More importantly, because I/O-bound work spends virtually no time on the CPU, dedicating an entire CPU thread to perform barely any useful work would be a poor use of resources. + +Additionally, dispatching work to the UI thread (such as updating a UI) is very simple with `async` methods, and does not require extra work (such as calling a thread-safe delegate). + +## Deeper Dive into Task and Task for a CPU-Bound Operation + +CPU-bound `async` code is a bit different than I/O-bound `async` code. Because the work is done on the CPU, there's no way to get around dedicating a thread to the computation. The use of `async` and `await` provides you with a clean way to interact with a background thread and keep the caller of the async method responsive. Note that this does not provide any protection for shared data. If you are using shared data, you will still need to apply an appropriate synchronization strategy. + +Here's a 10,000 foot view of a CPU-bound async call: + +```csharp +public async Task CalculateResult(InputData data) +{ + // This queues up the work on the threadpool. + var expensiveResultTask = Task.Run(() => DoExpensiveCalculation(data)); + + // Note that at this point, you can do some other work concurrently, + // as CalculateResult() is still executing! + + // Execution of CalculateResult is yielded here! + var result = await expensiveResultTask; + + return result; +} +``` + +`CalculateResult()` executes on the thread it was called on. When it calls `Task.Run`, it queues the expensive CPU-bound operation, `DoExpensiveCalculation()`, on the thread pool and receives a `Task` handle. `DoExpensiveCalculation()` is eventually run concurrently on the next available thread, likely on another CPU core. It's possible to do concurrent work while `DoExpensiveCalculation()` is busy on another thread, because the thread which called `CalculateResult()` is still executing. + +Once `await` is encountered, the execution of `CalculateResult()` is yielded to its caller, allowing other work to be done with the current thread while `DoExpensiveCalculation()` is churning out a result. Once it has finished, the result is queued up to run on the main thread. Eventually, the main thread will return to executing `CalculateResult()`, at which point it will have the result of `DoExpensiveCalculation()`. + +### Why does async help here? + +`async` and `await` are the best practice managing CPU-bound work when you need responsiveness. There are multiple patterns for using async with CPU-bound work. It's important to note that there is a small cost to using async and it's not recommended for tight loops. It's up to you to determine how you write your code around this new capability. \ No newline at end of file diff --git a/docs/async/async-overview.md b/docs/async/async-overview.md index 139bab895250c..bd79997d7c0c2 100644 --- a/docs/async/async-overview.md +++ b/docs/async/async-overview.md @@ -14,27 +14,27 @@ ms.assetid: 1e38e9d9-8284-46ee-a15f-199adc4f26f4 # Async Overview -Modern apps are expected to be responsive and modern services are expected to be elastic: +Not so long ago, apps got faster simply by buying a newer PC or server and then that trend stopped. In fact, it reversed. Mobile phones appeared with 1ghz single core ARM chips and server workloads transitioned to VMs. Users still want responsive UI and business owners want servers that scale with their business. The transition to mobile and cloud and an internet-connected population of >3B users has resulted in a new set of software patterns. -* Client applications are expected to be always-on and always-connected, but also keep the UI free for the user to interact with. -* Services are expected to handle spikes in traffic by gracefully scaling up and down. +* Client applications are expected to be always-on, always-connected and constantly responsive to user interaction (e.g. touch) with high app store ratings! +* Services are expected to handle spikes in traffic by gracefully scaling up and down. -.NET provides the capability for apps and services to be responsive and elastic with easy-to-use, language-level asynchronous programming models in C#, VB, and F#. +Async programming is a key technique that makes it straightforward to handle blocking I/O and concurrent operations on multiple cores. .NET provides the capability for apps and services to be responsive and elastic with easy-to-use, language-level asynchronous programming models in C#, VB, and F#. ## Why Write Async Code? -If you are developing a system which blocks on I/O in some way, you should be writing async code. If that doesn’t convince you, here are a few more reasons: +Modern apps make extensive use of file and networking I/O. I/O APIs traditionally block by default, resulting in poor user experiences and hardware utilization unless you want to learn and use challenging patterns. Async APIs and the language-level asynchronous programming model invert this model, making async execution the default with few new concepts to learn. -* Almost all modern apps demand elements which block on I/O in some way. Because of this, responsive apps are expected by users, and even slight UX hangups are often punished harshly (via one-star reviews). -* Modern web services must be able to handle a high load with the number of devices potentially connecting to them. Async programming allows scaling up so that sudden spikes in traffic don’t bring a system to its knees. -* Many of the newer, better .NET APIs are themselves asynchronous in nature. -* It’s super easy to write async code in .NET! +Async code has the following characteritics: -Especially in the case of F#, a functional-first language designed to solve problems at scale, asynchronous programming is a necessity for elastic services under a heavy load. +* Handles more server requests by yielding threads to handle more requests while waiting for I/O requests to return. +* Enables UIs to be more responsive by yielding threads to UI interaction while waiting for I/O requests and by transitioning long-running work to other CPU cores. +* Many of the newer .NET APIs are asynchronous. +* It’s super easy to write async code in .NET! ## What’s next? -Pick your language to learn about it: +Learn about async based on language experience: -* [Async Programming in C#](../languages/csharp/async.md) -* [Async Programming in F#](async-fsharp.md) +* [Async Programming in C#/VB](async-csharp-vb.md) +* [Async Programming in F#](async-fsharp.md) diff --git a/docs/languages/csharp/async.md b/docs/languages/csharp/async.md index 9021e34ed036e..367f2cd0f721e 100644 --- a/docs/languages/csharp/async.md +++ b/docs/languages/csharp/async.md @@ -14,44 +14,133 @@ ms.assetid: b878c34c-a78f-419e-a594-a2b44fa521a4 # Asynchronous programming -C# and Visual Basic share a language-level asynchronous programming model which allows for easily writing asynchronous code without having to juggle callbacks or conform to a library which supports asynchrony. It follows what is known as the [Task-based Asynchronous Pattern (TAP)](https://msdn.microsoft.com/library/hh873175.aspx). +If you have any I/O-bound needs (such as requesting data from a network or accessing a database), you'll want to utilize asynchronous programming. You could also have CPU-bound code, such as performing an expensive calculation, which is also a good scenario for writing async code. -The core of TAP are the `Task` and `Task` objects, which model asynchronous operations, supported by the `async` and `await` keywords (`Async` and `Await` in VB), which provide a natural developer experience for interacting with Tasks. The result is the ability to write asynchronous code which cleanly expresses intent, as opposed to callbacks which express intent far less cleanly. There are other ways to approach async code than `async` and `await` outlined in the TAP article linked above, but this document will focus on the language-level constructs from this point forward. +C# has a language-level asynchronous programming model which allows for easily writing asynchronous code without having to juggle callbacks or conform to a library which supports asynchrony. It follows what is known as the [Task-based Asynchronous Pattern (TAP)](https://msdn.microsoft.com/en-us/library/hh873175%28v=vs.110%29.aspx). -For example, you may need to download some data from a web service when a button is pressed, but don’t want to block the UI thread. It can be accomplished simply like this: +## Basic Overview of the Asynchronous Model -```cs -private readonly HttpClient _httpClient = new HttpClient(); +The core of async programming are the `Task` and `Task` objects, which model asynchronous operations. They are supported by the `async` and `await` keywords. The model is fairly simple in most cases: + +For I/O-bound code, you `await` an operation which returns a `Task` or `Task` inside of an `async` method. + +For CPU-bound code, you `await` an operation which is started on a background thread with the `Task.Run` method. + +The `await` keyword is where the magic happens, because it yields control to the caller of the method which performed the `await`. It is what ultimately allows a UI to be responsive, or a service to be elastic. + +There are other ways to approach async code than `async` and `await` outlined in the TAP article linked above, but this document will focus on the language-level constructs from this point forward. + +### I/O-Bound Example: Downloading data from a web service -... +You may need to download some data from a web service when a button is pressed, but don’t want to block the UI thread. It can be accomplished simply like this: -button.Clicked += async (o, e) => +```csharp +private readonly HttpClient _httpClient = new HttpClient(); + +downloadButton.Clicked += async (o, e) => { - var stringData = await _httpClient.DownloadStringAsync(URL); - DoStuff(stringData); + // This line will yield control to the UI as the request + // from the web service is happening. + // + // The UI thread is now free to perform other work. + var stringData = await _httpClient.GetStringAsync(URL); + DoSomethingWithData(stringData); }; - ``` And that’s it! The code expresses the intent (downloading some data asynchronously) without getting bogged down in interacting with Task objects. -For those who are more theoretically-inclined, this is an implementation of the [Future/Promise concurrency model](https://en.wikipedia.org/wiki/Futures_and_promises). +### CPU-bound Example: Performing a Calculation for a Game + +Say you're writing a mobile game where pressing a button can inflict damage on many enemies on the screen. Performing the damage calcuation can be expensive, and doing it on the UI thread would make the game appear to pause as the calculation is performed! + +The best way to handle this is to start a background thread which does the work using `Task.Run`, and `await` its result. This will allow the UI to feel smooth as the work is being done. + +```csharp +private DamageResult CalculateDamageDone() +{ + // Code omitted: + // + // Does an expensive calculation and returns + // the result of that calculation. +} + + +calculateButton.Clicked += async (o, e) => +{ + // This line will yield control to the UI CalculateDamageDone() + // performs its work. The UI thread is free to perform other work. + var damageResult = await Task.Run(() => CalculateDamageDone()); + DisplayDamage(damageResult); +}; +``` + +And that's it! This code cleanly expresses the intent of the button's click event, it doesn't require managing a background thread manually, and it does so in a non-blocking way. + +### What happens under the covers -A few important things to know before continuing: +There's a lot of moving pieces where asynchronous operations are concerned. If you're curious about what's happening underneath the covers of `Task` and `Task`, checkout the [Async in-depth](../../async/async-in-depth.md) article for more information. -* Async code uses `Task` and `Task`, which are constructs used to model the work being done in an asynchronous context. [More on Task and Task](#more-on-task-and-task-t) -* When the `await` keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. This is what allows a UI to be responsive and a service to be elastic. +On the C# side of things, the compiler transforms your code into a state machine which keeps track of things like yielding execution when an `await` is reached and resuming execution when a background job has finished. + +For the theoretically-inclined, this is an implementation of the [Promise Model of asynchrony](https://en.wikipedia.org/wiki/Futures_and_promises). + +## Key Pieces to Understand + +* Async code can be used for both I/O-bound and CPU-bound code, but differently for each scenario. +* Async code uses `Task` and `Task`, which are constructs used to model work being done in the background. +* 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. -* Unless an async method has an `await` inside its body, it will never yield! -* `async void` should **only** be used on Event Handlers (where it is required). -## Example (C#) +## Recognize CPU-Bound and I/O-Bound Work + +The first two examples of this guide showed how you can use `async` and `await` for I/O-bound and CPU-bound work. It's key that you can identify when a job you need to do is I/O-bound or CPU-bound, because it can greatly affect the performance of your code and could potentially lead to misusing certain constructs. + +Here are two questions you should ask before you write any code: + +1. Will you code be "waiting" for something, such as data from a database? + + If your answer is "yes", then your work is **I/O-bound**. + +2. Will your code be performing a very expensive computation? + + If you answered "yes", then your work is **CPU-bound**. + +If the work you have is **I/O-bound**, use `async` and `await` *without* `Task.Run`. You *should not* use the Task Parallel Library. The reason for this is outlined in the [Async in Depth article](../../async/async-in-depth.md). + +If the work you have is **CPU-bound** and you care about responsiveness, use `async` and `await` but spawn the work off on another thread *with* `Task.Run`. If the work is appropriate for concurrency and parallelism, you should also consider using the Task Parallel Library. -The following example shows how to write basic async code for both a client app and a web service. The code, in both cases, will count the number of times ”.NET” appears in the HTML of “dotnetfoundation.org”. +Additionally, you should always measure the execution of your code. For example, you may find yourself in a situation where your CPU-bound work is not costly enough compared with the overhead of context switches when multithreading. Every choice has its tradeoff, and you should pick the correct tradeoff for your situation. -Client app snippet (Universal Windows App): +## More Examples -```cs +The following examples demonstrate various ways you can write async code in C#. They cover a few different scenarios you may come across. + +### Extracting Data from a Network + +This snippet downloads the HTML from www.dotnetfoundation.org and counts the number of times the string ".NET" occurs in the HTML. It uses ASP.NET MVC to define a web controller method which performs this task, returning the number. + +*Note: you shouldn't ever use Regexes if you plan on doing actual HTML parsing. Please using a parsing library if this is your aim in production code.* + +```csharp +private readonly HttpClient _httpClient = new HttpClient(); + +[HttpGet] +[Route("DotNetCount")] +public async Task GetDotNetCountAsync() +{ + // Suspends GetDotNetCountAsync() to allow the caller (the web server) + // to accept another request, rather than blocking on this one. + var html = await _httpClient.DownloadStringAsync("http://dotnetfoundation.org"); + + return Regex.Matches(html, ".NET").Count; +} +``` + +Here's the same scenario written for a Universal Windows App, which performs the same task when a Button is pressed: + +```csharp private readonly HttpClient _httpClient = new HttpClient(); private async void SeeTheDotNets_Click(object sender, RoutedEventArgs e) @@ -75,60 +164,65 @@ private async void SeeTheDotNets_Click(object sender, RoutedEventArgs e) NetworkProgressBar.IsEnabled = false; NetworkProgressBar.Visbility = Visibility.Collapsed; } - ``` -Web service snippet (ASP.NET MVC): +### Waiting for Multiple Tasks to Complete -```cs -private readonly HttpClient _httpClient = new HttpClient(); +You may find yourself in a situation where you need to retrieve multiple pieces of data concurrently. The `Task` API contains two methods, `Task.WhenAll` and `Task.WhenAny` which allow you to write asynchronous code which performs a non-blocking wait on mulitple background jobs. -[HttpGet] -[Route("DotNetCount")] -public async Task GetDotNetCountAsync() -{ - // Suspends GetDotNetCountAsync() to allow the caller (the web server) - // to accept another request, rather than blocking on this one. - var html = await _httpClient.DownloadStringAsync("http://dotnetfoundation.org"); +This example shows how you might grab `User` data for a set of `userId`s. - return Regex.Matches(html, ".NET").Count; +```csharp + +public async Task GetUser(int userId) +{ + // Code omitted: + // + // Given a user Id {userId}, retrieves a User object corresponding + // to the entry in the database with {userId} as its Id. } +public static Task> GetUsers(IEnumerable userIds) +{ + var getUserTasks = new List>(); + + foreach (int userId in userIds) + { + getUserTasks.Add(GetUser(id)); + } + + return await Task.WhenAll(getUserTasks); +} ``` -## More on Task and Task - -As mentioned before, Tasks are constructs used to represent operations working in the background. - -* `Task` represents a single operation which does not return a value. -* `Task` represents a single operation which returns a value of type `T`. - -Tasks are awaitable, meaning that using `await` will allow your application or service to perform useful work while the task is running by yielding control to its caller until the task is done. If you’re using `Task`, the `await` keyword will additionally “unwrap” the value returned when the Task is complete. - -It’s important to reason about Tasks as abstractions of work happening in the background, and _not_ an abstraction over multithreading. In fact, unless explicitly started on a new thread via `Task.Run`, a Task will start on the current thread and delegate work to the Operating System. - -Here’s a 10,000 foot view of what happens with a typical async call: - -The call (such as `GetStringAsync` from `HttpClient`) makes its way through the .NET libraries until it reaches a system interop call (such as `P/Invoke` on Windows). This eventually makes the proper System API call (such as `write` to a socket file descriptor on Linux). That System API call is then dealt with in the kernel, where the I/O request is sent to the proper subsystem. Although details about scheduling the work on the appropriate device driver are different for each OS, eventually an “incomplete task” signal will be sent from the device driver, bubbling its way back up to the .NET runtime. This will be converted into a `Task` or `Task` by the runtime and returned to the calling method. When `await` is encountered, execution is yielded and the system can go do something else useful while the Task is running. - -When the device driver has the data, it sends an interrupt which eventually allows the OS to bubble the result back up to the runtime, which will the queue up the result of the Task. Eventually execution will return to the method which called `GetStringAsync` at the `await`, and will “unwrap” the return value from the `Task` which was being awaited. The method now has the result! +Here's another way to write this a bit more succinctly, using LINQ: -Although many details were glossed over (such as how “borrowing” compute time on a thread pool is coordinated), the important thing to recognize here is that **no thread is 100% dedicated to running the initiated task**. This allows threads in the thread pool of a system to handle a larger volume of work rather than having to wait for I/O to finish. +```csharp -Although the above may seem like a lot of work to be done, when measured in terms of wall clock time, it’s miniscule compared to the time it takes to do the actual I/O work. Although not at all precise, a potential timeline for such a call would look like this: - -0-1————————————————————————————————————————————————–2-3 - -* Time spent from points `0` to `1` is everything up until an async method yields control to its caller. -* Time spent from points `1` to `2` is the time spent on I/O. -* Finally, time spent from points `2` to `3` is passing control back (and potentially a value) to the async method, at which point it is executing again. +public async Task GetUser(int userId) +{ + // Code omitted: + // + // Given a user Id {userId}, retrieves a User object corresponding + // to the entry in the database with {userId} as its Id. +} -Tasks are also used outside of the async programming model. They are the foundation of the Task Parallel Library, which supports the parallelization of CPU-bound work via [Data Parallelism](https://msdn.microsoft.com/library/dd537608.aspx) and [Task Parallelism](https://msdn.microsoft.com/library/dd537609.aspx). +public static async Task GetUsers(IEnumerable userIds) +{ + var getUserTasks = userIds.Select(id => GetUser(id)); + return await Task.WhenAll(getUserTasks); +} +``` +Although it's less code, take care when mixing LINQ with asynchronous code. Because LINQ uses deferred (lazy) execution, async calls won't happen immediately as they do in a `foreach()` loop unless you force the generated sequence to iterate with a call to `.ToList()` or `.ToArray()`. ## Important Info and Advice Although async programming is relatively straightforward, there are some details to keep in mind which can prevent unexpected behavior. +* `async` **methods need to have an** `await` **keyword in their body or they will never yield!** + +This is important to keep in mind. If `await` is not used in the body of an `async` method, the C# compiler will generate a warning, but the code will compile and run as if it were a normal method. Note that this would also be incredibly inefficient, as the state machine generated by the C# compiler for the async method would not be accomplishing anything. + * **You should add “Async” as the suffix of every async method name you write.** This is the convention used in .NET to more-easily differentiate synchronous and asynchronous methods. Note that certain methods which aren’t explicitly called by your code (such as event handlers or web controller methods) don’t necessarily apply. Because these are not explicitly called by your code, being explicit about their naming isn’t as important. @@ -169,3 +263,6 @@ Don’t depend on the state of global objects or the execution of certain method A recommended goal is to achieve complete or near-complete [Referential Transparency](https://en.wikipedia.org/wiki/Referential_transparency_%28computer_science%29) in your code. Doing so will result in an extremely predictable, testable, and maintainable codebase. +## Other Resources + +* Lucian Wischik's [Six Essential Tips for Async](https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async) are a wonderful resource for async programming \ No newline at end of file diff --git a/images/async/io-1.jpg b/images/async/io-1.jpg new file mode 100644 index 0000000000000..41e6e0edaaca2 Binary files /dev/null and b/images/async/io-1.jpg differ diff --git a/images/async/io-2.jpg b/images/async/io-2.jpg new file mode 100644 index 0000000000000..7a2c4acf1eec6 Binary files /dev/null and b/images/async/io-2.jpg differ diff --git a/images/async/ui.jpg b/images/async/ui.jpg new file mode 100644 index 0000000000000..55ebb403081f5 Binary files /dev/null and b/images/async/ui.jpg differ diff --git a/images/async/webserver-1.jpg b/images/async/webserver-1.jpg new file mode 100644 index 0000000000000..05d62bdefd98e Binary files /dev/null and b/images/async/webserver-1.jpg differ diff --git a/images/async/webserver-2.jpg b/images/async/webserver-2.jpg new file mode 100644 index 0000000000000..4aff3c5c725b3 Binary files /dev/null and b/images/async/webserver-2.jpg differ