async and await on the server
TRANSCRIPT
![Page 1: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/1.jpg)
Async and Await on the Server
Doug Jones
![Page 2: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/2.jpg)
So…what’s this about? Task-based Asynchronous Pattern on the server
What is it? Why use it? How does it work?
Or…everything I wish I knew about async/await when I started using it!
![Page 3: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/3.jpg)
Life is Asynchronous!Cooking a Spaghetti Dinner
Fill pot with water Put pot on stove Start boiling water (async) Do dishes When water is boiling… (await) Put spaghetti in boiling water (async) Start warming up pasta sauce (async) Make salad Pour drinks When spaghetti and sauce finished… (await) Make plates of spaghetti with sauce and side salad
![Page 4: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/4.jpg)
Synchronous Cooking! Fill pot with water Put pot on stove Wait for water to boil (just stare at it) Put spaghetti in pot Wait for spaghetti to cook (stare harder) Strain spaghetti Fill another pan with pasta sauce Put pasta sauce on stove Wait for pasta sauce to warm up (keep staring…maybe it helps?) Make salad Pour drinks Make plates of spaghetti with sauce and side salad
![Page 5: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/5.jpg)
Cooking Dinner – The Codepublic async Task<Dinner> MakeDinnerAsync() { Task boilWaterTask = BoilWaterAsync(); DoDishes(); await boilWaterTask; Task<Spaghetti> boilSpaghettiTask = BoilSpaghettiAsync(); Task<PastaSauce> warmPastaSauceTask = WarmPastaSauceAsync(); Salad salad = MakeSalad(); Drink drink = GetDrink(); await Task.WhenAll(boilSpaghettiTask, warmPastaSauceTask); Spaghetti spaghetti = await boilSpaghettiTask; PastaSauce pastaSauce = await warmPastaSauceTask; Dinner dinner = MakeDinnerPlate(spaghetti, pastaSauce, salad, drink); return dinner; }
![Page 6: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/6.jpg)
This is not about…
Other forms of concurrency in the Task Parallel Library (TPL) Data Parallelism (Parallel.For and ForEach) Task Parallelism (Tasks without async/await) Parallel LINQ (PLINQ) TPL Dataflow
![Page 7: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/7.jpg)
Process – High Level An instance of a program running on a
computer In IIS, a w3wp.exe worker process runs for
every app pool you have running NOT for every web application *Side Note* Running multiple worker
processes for same web application called a Web Garden
![Page 8: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/8.jpg)
Thread – High Level By this I mean .NET CLR MANAGED threads 1 or more threads to a process
1 Megabyte memory per thread stack reservation size (by default) Expensive to allocate and garbage collect Multi-Core compatible
Using multiple likely means using multiple cores Threads distributed amongst CPUs by OS
![Page 9: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/9.jpg)
Threadpool – High Level
A “pool” or collection of .NET managed threads Background worker threads managed by the system
For quick work without the overhead of allocating a new thread Only 1 threadpool per process
![Page 10: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/10.jpg)
Async in ASP.NET video - Levi Broderick
IIS requests – High Level
In ASP.NET, AVOID using thread pool threads
![Page 11: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/11.jpg)
Avoid Threadpool usage in ASP.NET
Request made in ASP.NET uses a threadpool thread That includes any mechanisms that use threadpool threads
Basically all compute bound parallel processing PLINQ Task.Run Task.Factory.StartNew Parallel.For
![Page 12: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/12.jpg)
Promises and Futures Promise - a writable, single assignment container which sets the
value of the future (via .SetResult in C#) C# - TaskCompletionSource Java – SettableFuture jQuery - $.Deferred() AngularJs - $q.defer() ES6 – don’t have direct access, but call resolve or reject within passed in
function
Future - read-only placeholder view of a variable C# - Task or Task<T> Java - Future jQuery - $.Deferred().promise AngularJs - $q.defer().promise ES6 - new Promise( function (resolve, reject) { ... })
![Page 13: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/13.jpg)
What is async/await?
Asynchronous programming made easy! Almost as easy to do async as it is to do synchronous programming
Ties in to Task Parallel Library’s Task functionality A new language feature in .NET 4.5
Async/Await released with C# 5.0 (.NET 4.5), released August 2012 Can compile using VS 2012+
![Page 14: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/14.jpg)
Why async/await? For network I/O
Web service calls Database calls Cache calls Any call to any other server
Something else doing the work Computationally intensive work using Task.Run (avoid in ASP.NET)
It is doing the work
![Page 15: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/15.jpg)
What methods can be async?
Methods with the following return types can be made async Task Task<T> void //but avoid it!
async Task async Task<T> async void
![Page 16: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/16.jpg)
Task – High Level
Multi-core compatible Unit of Work POTENTIALLY asynchronous operation
![Page 17: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/17.jpg)
Tasks are like IOUs…Task t = GetTaskAsync(); Active task when not… t.IsCompleted t.IsFaulted t.IsCanceled
![Page 18: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/18.jpg)
Synchronous Method
ASYNChronous Methodprivate async Task<string> GetUrlAsync(string url) { using (var client = new HttpClient()) { return await client.GetStringAsync(url); //network I/O, thread not blocking } }
private string GetUrl(string url) { using (var client = new WebClient()) { return client.DownloadString(url); } }
![Page 19: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/19.jpg)
What does the async keyword do? Lets the method know that it can have await keyword Tells the method to wrap the returned value in a Task Tells the compiler to generate a LOT of code (another slide) It’s an implementation detailpublic interface IHttpService { Task<string> GetUrlAsync(string url); } public class HttpService : IHttpService { public async Task<string> GetUrlAsync(string url) { string result; using (var client = new HttpClient()) { result = await client.GetStringAsync(url); //network I/O } return result; } }
![Page 20: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/20.jpg)
So…why use it?private static readonly List<string> Urls = new List<string> { "http://blogs.msdn.com/b/pfxteam/", "http://blog.stephencleary.com/", "https://channel9.msdn.com/", "http://www.pluralsight.com/", "http://stackoverflow.com/" };
[HttpGet] [Route("geturlssync")] public string GetUrls() { var watch = Stopwatch.StartNew(); var urlResults = new List<string>(); foreach (string url in Urls) { urlResults.Add(GetUrl(url)); } //LINQ select via method group syntax //var urlResults = Urls.Select(GetUrl); return watch.ElapsedMilliseconds.ToString(); }
Test took 3.2 seconds to run
![Page 21: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/21.jpg)
So…why use it? cont’d[HttpGet] [Route("geturlsasync")] public async Task<string> GetUrlsAsync() { var watch = Stopwatch.StartNew(); var urlResultsTasks = new List<Task<string>>(); foreach (string url in Urls) { urlResultsTasks.Add(GetUrlAsync(url)); } //LINQ select via method group syntax //var urlResultsTasks = Urls.Select(GetUrlAsync); await Task.WhenAll(urlResultsTasks); return watch.ElapsedMilliseconds.ToString(); }
Test took 1.5 seconds to run AND fewer server resources
![Page 22: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/22.jpg)
Control Flow
https://msdn.microsoft.com/en-us/library/hh191443.aspx
![Page 23: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/23.jpg)
All About Tasks…
using System.Threading.Tasks;
![Page 24: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/24.jpg)
Task.Delay
Replacement for Thread.Sleep Returns completed task after a specified delay
await Task.Delay(1000);
Don’t use Thread.Sleep with async tasks!
![Page 25: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/25.jpg)
WhenAny – more advanced[HttpGet] [Route("getfromcacheordb")] public async Task<string> GetFromCacheOrDb() { string retVal = null; var getFromCacheTask = GetFromCacheAsync(); await Task.WhenAny(getFromCacheTask, Task.Delay(2000)); if (getFromCacheTask.IsCompleted) { retVal = await getFromCacheTask; //perfectly safe to use getFromCacheTask.Result here //but I won't…see the DANGER ZONE section } else { var getFromDbTask = GetFromDbAsync(); var taskWithData = await Task.WhenAny(getFromCacheTask, getFromDbTask); retVal = await taskWithData; } return retVal; }
![Page 26: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/26.jpg)
Generated Async code
public Task<string> GetUrlAsync(string url) { HttpService.\u003CGetUrlAsync\u003Ed__0 stateMachine; stateMachine.\u003C\u003E4__this = this; stateMachine.url = url; stateMachine.\u003C\u003Et__builder = AsyncTaskMethodBuilder<string>.Create(); stateMachine.\u003C\u003E1__state = -1; stateMachine.\u003C\u003Et__builder.Start<HttpService.\u003CGetUrlAsync\u003Ed__0>(ref stateMachine); return stateMachine.\u003C\u003Et__builder.Task; }
public async Task<string> GetUrlAsync(string url) { string result; using (HttpClient httpClient = new HttpClient()) result = await httpClient.GetStringAsync(url); return result; }
compiles to…
![Page 27: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/27.jpg)
Generated Async Code cont’d [CompilerGenerated] [StructLayout(LayoutKind.Auto)] private struct \u003CGetUrlAsync\u003Ed__0 : IAsyncStateMachine { public int \u003C\u003E1__state; public AsyncTaskMethodBuilder<string> \u003C\u003Et__builder; public HttpService \u003C\u003E4__this; public string url; public string \u003Cresult\u003E5__1; public HttpClient \u003Cclient\u003E5__2; private TaskAwaiter<string> \u003C\u003Eu__\u0024awaiter3; private object \u003C\u003Et__stack;
void IAsyncStateMachine.MoveNext() { string result1; try { bool flag = true; switch (this.\u003C\u003E1__state) { case -3: break; case 0: try { TaskAwaiter<string> awaiter; if (this.\u003C\u003E1__state != 0) { awaiter = this.\u003Cclient\u003E5__2.GetStringAsync(this.url).GetAwaiter(); if (!awaiter.IsCompleted) { this.\u003C\u003E1__state = 0; this.\u003C\u003Eu__\u0024awaiter3 = awaiter; this.\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, HttpService.\u003CGetUrlAsync\u003Ed__0>(ref awaiter, ref this); flag = false; return; } } else { awaiter = this.\u003C\u003Eu__\u0024awaiter3; this.\u003C\u003Eu__\u0024awaiter3 = new TaskAwaiter<string>(); this.\u003C\u003E1__state = -1; } string result2 = awaiter.GetResult(); TaskAwaiter<string> taskAwaiter = new TaskAwaiter<string>(); this.\u003Cresult\u003E5__1 = result2; } finally { if (flag && this.\u003Cclient\u003E5__2 != null) this.\u003Cclient\u003E5__2.Dispose(); } result1 = this.\u003Cresult\u003E5__1; break; default: this.\u003Cclient\u003E5__2 = new HttpClient(); goto case 0; } } catch (Exception ex) { this.\u003C\u003E1__state = -2; this.\u003C\u003Et__builder.SetException(ex); return; } this.\u003C\u003E1__state = -2; this.\u003C\u003Et__builder.SetResult(result1); }
[DebuggerHidden] void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0) { this.\u003C\u003Et__builder.SetStateMachine(param0); } }
![Page 28: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/28.jpg)
SynchronizationContext.NET applications have a synchronization contextIt’s different for each type of app, but fall into buckets ASP.NET
MVC WebAPI WebForms
UI WPF WinForms Windows Store app
Neither Console app
![Page 29: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/29.jpg)
SynchronizationContext suggestions
If it’s on the UI or in ASP.NET and you don’t need the context…don’t continue on captured context
public async Task<string> GetUrlAsync(string url) { string result = await GetUrlAsync(url, CancellationToken.None).ConfigureAwait(false); return result; }
![Page 30: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/30.jpg)
[HttpGet] [Route("getrequesturl")] public async Task<string> GetRequestUrl() { await DoingSomethingAsync().ConfigureAwait(continueOnCapturedContext: false); // And now we're on the thread pool thread without a captured context //so the HttpContext.Current is null //so...UNHANDLED EXCEPTION without compiler warning! return HttpContext.Current.Request.RawUrl; }
SynchronizationContext suggestions cont’d
But there are places where you do need the context…
![Page 31: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/31.jpg)
My rule of thumb:
Don’t use .ConfigureAwait(false) on endpoints and ASP.NET pipeline MVC controller actions WebAPI actions Filters HttpHandlers Http Message Handlers like DelegatingHandler
Use .ConfigureAwait(false) basically everywhere else
SynchronizationContext suggestions cont’d
![Page 32: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/32.jpg)
![Page 33: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/33.jpg)
The DANGER ZONE
![Page 34: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/34.jpg)
The Deadlock with .Result or .Wait() Don’t do .Result or .Wait() on unfinished task
Or at all…
[HttpGet] [Route("deadlockdemo")] public string DeadlockDemo() { string urlContent = _httpService.GetUrlAsync("http://finance.yahoo.com").Result; return urlContent; }
public async Task<string> GetUrlAsync(string url) { string result = await GetUrlAsync(url, CancellationToken.None); return result; }
AspNetSynchronizationContext will ensure that they execute one at a timehttps://msdn.microsoft.com/en-us/magazine/gg598924.aspx
![Page 35: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/35.jpg)
The Deadlock cont’d
![Page 36: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/36.jpg)
The Deadlock cont’dRemember the SynchronizationContext?
[HttpGet] [Route("deadlockdemo")] public async Task<string> DeadlockDemo() { string urlContent = _httpService.GetUrlAsync("http://finance.yahoo.com").Result; return urlContent; }
public async Task<string> GetUrlAsync(string url) { string result = await GetUrlAsync(url, CancellationToken.None).ConfigureAwait(false); return result; }
If ALL awaited tasks are set to configureawait false, the block won’t cause a deadlock
![Page 37: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/37.jpg)
Synchronous Methodpublic string Echo(string message)
{
return message;
}
ALSO Synchronous Methodpublic async Task<string> EchoAsync(string message) { return message; }10x SLOWER!
![Page 38: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/38.jpg)
ALSO Synchronous
public Task<string> EchoAsync2(string message) { return Task.FromResult(message); }
10x SLOWER!
2.5x SLOWER!
public async Task<string> EchoAsync3(string message) { return await Task.FromResult(message); }
![Page 39: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/39.jpg)
Asynchronous, but in Parallel public async Task<string> GetUrlAsync2() { string result = await Task.Run(async () => await _httpService.GetUrlAsync("http://blogs.msdn.com/b/pfxteam/") ); return result; }
Already an async call, no need for parallel
![Page 40: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/40.jpg)
Synchronous as parallel async?
[HttpGet] [Route("syncasasync")] public async Task<string> SyncAsParallelAsync() { string retVal = await Task.Run(() => GetUrl("http://blog.stephencleary.com/")); return retVal; }
![Page 41: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/41.jpg)
But I need to call an async method synchronously! IF you can’t change the interface
Can’t change from return of string to return of Task<string> that gets awaited
[HttpGet] [Route("asyncassync")] public string AsyncAsSync() { string cachedItem = Task.Run(() => GetFromCacheAsync(CancellationToken.None)).Result; return cachedItem; }
Avoid if at all possible!
![Page 42: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/42.jpg)
Async void
Avoid async void! Only use async void if you MUST conform to prior interface.
Primarily for events
private async void btnDownload_Click(object sender, RoutedEventArgs e) { btnDownload.IsEnabled = false; try { txtResult.Text = await DownloadStringAsync(txtUrl.Text, new Progress<int>(p => pbDownloadProgress.Value = p)); } finally { btnDownload.IsEnabled = true; }}
![Page 43: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/43.jpg)
Async All The WayOnce you start, you can’t stop…
public static async Task<T> MakeHttpRequestAsync<T>(…)
private async Task<TResult> GetHttpAsync<T, TResult>(…)
public async Task<TResponse> GetRulesEngineResponseAsync(…)
private async Task<SavingsRulesResponse> GetSavingsRulesAsync(…)
public async Task<ExperimentTemplate> CallToActionBuilderAsync(…)
private Task GenerateCallsToActionAndRespondAsync(…)
[System.Web.Http.Route("generatecallstoaction")][HttpPost]public async Task<ApiResponseActionResult> GenerateCallsToActionAsync(…)
![Page 44: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/44.jpg)
Back to the regularly scheduled talk…
using System.Threading.Tasks;
![Page 45: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/45.jpg)
Cancellations[HttpGet] [Route("geturlsasync")] public async Task<string> GetUrlsAsync() { var watch = Stopwatch.StartNew(); var cts = new CancellationTokenSource(1000); var urlResultsTasks = new List<Task<string>>(); try { urlResultsTasks = Urls.Select(url => _httpService.GetUrlAsync(url, cts.Token)).ToList(); await Task.WhenAll(urlResultsTasks); } catch (TaskCanceledException ex) { //swallow ex for now } return string.Format("Cancelled Tasks: {0} Elapsed Time In MS: {1}", urlResultsTasks.Count(x => x.IsCanceled), watch.ElapsedMilliseconds); }
OUTPUT: "Cancelled Tasks: 1 Elapsed Time In MS: 1152"
![Page 46: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/46.jpg)
Cancellations cont’dThe trickle down effect of cancellation code
public async Task<string> GetUrlAsync(string url,CancellationToken cancellationToken) { string result; var uri = new Uri(url); using (var client = new HttpClient()) {
cancellationToken.ThrowIfCancellationRequested(); //optional var response = await client.GetAsync(uri, cancellationToken); //network I/O cancellationToken.ThrowIfCancellationRequested(); //optional result = await response.Content.ReadAsStringAsync(); //potentially network I/O } return result; }
![Page 47: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/47.jpg)
Cancellations linked[HttpGet] [Route("geturlsasync2")] //[AsyncTimeout(1500)] for MVC only public async Task<string> GetUrlsAsync2(CancellationToken cancellationToken) { var watch = Stopwatch.StartNew(); var cts = new CancellationTokenSource(1000); var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token); var urlResultsTasks = new List<Task<string>>(); try { urlResultsTasks = Urls.Select(url => _httpService.GetUrlAsync(url, linkedCts.Token)).ToList(); await Task.WhenAll(urlResultsTasks); } catch (TaskCanceledException ex) { //swallow ex for now }
return string.Format("Cancelled Tasks: {0} Elapsed Time In MS: {1}", urlResultsTasks.Count(x => x.IsCanceled), watch.ElapsedMilliseconds); }
![Page 48: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/48.jpg)
Async lambdasCan use async on Action<T> and Func<T> types
[HttpGet] [Route("asynclambda")] public async Task<string> AsyncLambda() { string closureMessage = null; var task = ExecuteAsyncAndLogTime("GetFromCacheAsync", async () => { closureMessage = await GetFromCacheAsync(CancellationToken.None); }); await task; return closureMessage; }
private async Task ExecuteAsyncAndLogTime(string title, Func<Task> asyncAction) { var watch = Stopwatch.StartNew(); await asyncAction.Invoke(); Debug.WriteLine("{0} ElapsedTimeInMs: {1}", title, watch.ElapsedMilliseconds); }
![Page 49: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/49.jpg)
Async lambdas cont’dThe Try Tri!
public static async Task<T> DoAsync<T>(Func<Task<T>> action, TimeSpan retryInterval, int retryCount = 3) { var exceptions = new List<Exception>(); for (int retry = 0; retry < retryCount; retry++) { if (retry > 0) { await Task.Delay(retryInterval); } try { return await action(); } catch (Exception ex) { exceptions.Add(ex); } } throw new AggregateException(exceptions); }
![Page 50: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/50.jpg)
Task.FromResult
[HttpGet] [Route("fromresult")] public async Task<string> FromResult() { string closureMessage = null; var task = ExecuteAsyncAndLogTime("Synchronous",() => { closureMessage = GetText(); return Task.FromResult(0); //.NET 4.6 has Task.CompletedTask for this }); await task; return closureMessage; }
![Page 51: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/51.jpg)
Hot and Cold methods
All async tasks run HOT As soon as task created, method is started (like regular method)
[HttpGet] [Route("getfromcache")] public async Task<string> GetFromCache() { var getFromCacheTask = GetFromCacheAsync(CancellationToken.None); SomethingSynchronous(); string cachedItem = await getFromCacheTask; return cachedItem; }
Note: GetFromCacheAsync takes 0.5 seconds and SomethingSynchronous takes 1 second
Total time was 1.149 seconds
![Page 52: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/52.jpg)
Cold Tasks (.NET 4.0)[HttpGet] [Route("coldtask")] public void ColdTask() { var task = new Task(() => { SomethingSynchronous(); // ...and some more stuff }); task.Start(); }
If you have a need, could be useful for computationally bound asynchrony, but…
You should probably AVOID this
![Page 53: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/53.jpg)
Exceptions
[HttpGet] [Route("throwerror")] public async Task<string> ThrowErrorAsync() { string message = null; var t = ThrowErrorCoreAsync(); try { message = await t; } catch (Exception ex) { return "ERROR awaiting"; } return message; } private async Task<string> ThrowErrorCoreAsync() { throw new Exception("Error!"); await GetFromDbAsync(CancellationToken.None); }
Work basically how you’d expect…
![Page 54: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/54.jpg)
Exceptions cont’d
Well…almostprivate async Task GetMultipleErrorsAsync() { var t1 = ThrowErrorCoreAsync(); var t2 = ThrowErrorCoreAsync2(); var t3 = ThrowErrorCoreAsync3();
var tAll = Task.WhenAll(t1, t2, t3); try { await tAll; } catch (Exception ex) { Debugger.Break(); } }
Exception thrown is error from t1, but tAll has AggregateException of all 3 errors
![Page 55: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/55.jpg)
![Page 56: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/56.jpg)
Aync Http
public async Task<string> GetUrlAsync(string url,CancellationToken cancellationToken) { string result; var uri = new Uri(url); using (var client = new HttpClient()) { var response = await client.GetAsync(uri, cancellationToken).ConfigureAwait(false); //network I/O result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); //potentially network I/O } return result; }
![Page 57: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/57.jpg)
Service References
![Page 58: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/58.jpg)
Service References cont’d
public static async Task Foo() { using (ServiceReference1.Service1Client client = new ServiceReference1.Service1Client()) { Task<string> t = client.GetDataAsync(1); string result = await t; } }
![Page 59: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/59.jpg)
ADO.NET
using (SqlConnection connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); using (SqlCommand command = new SqlCommand(commandString, connection)) { using (SqlDataReader reader = await command.ExecuteReaderAsync()) { //Some code if (await reader.ReadAsync()) { //more code } //Other code } } }
![Page 60: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/60.jpg)
Entity Framework 6public static async Task PerformDatabaseOperations() { using (var db = new BloggingContext()) { // Create a new blog and save it db.Blogs.Add(new Blog { Name = "Test Blog #" + (db.Blogs.Count() + 1) }); Console.WriteLine("Calling SaveChanges."); await db.SaveChangesAsync(); Console.WriteLine("SaveChanges completed."); // Query for all blogs ordered by name Console.WriteLine("Executing query."); var blogs = await (from b in db.Blogs orderby b.Name select b).ToListAsync(); // Write all blogs out to Console Console.WriteLine("Query completed with following results:"); foreach (var blog in blogs) { Console.WriteLine(" - " + blog.Name); } } }
![Page 61: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/61.jpg)
EF 6 stored procedure asyncwith Table-Valued Parameterpublic async Task UpdateSoftOfferEndpointsActiveFlag(Dictionary<string, bool> softOfferEndpointDictionary) { const string sql = "exec [SavingsEngine].[pUpdateSoftOfferEndpointsActiveFlag] @ipSoftOfferEndpointDictionary"; if (softOfferEndpointDictionary == null || !softOfferEndpointDictionary.Any()) { return; } var ipSoftOfferEndpointDictionaryParameter = new SqlParameter("@ipSoftOfferEndpointDictionary", System.Data.SqlDbType.Structured) { TypeName = "SavingsEngine.DictionaryStringBit" }; var temp = new System.Data.DataTable(); temp.Columns.Add("Key", typeof(string)); temp.Columns.Add("Value", typeof(bool)); foreach (var kvp in softOfferEndpointDictionary) { temp.Rows.Add(kvp.Key, kvp.Value); } ipSoftOfferEndpointDictionaryParameter.Value = temp; await _cbasContext.Database.ExecuteSqlCommandAsync(sql, ipSoftOfferEndpointDictionaryParameter).ConfigureAwait(false); }
![Page 62: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/62.jpg)
RedisStackExchange.Redishttps://github.com/StackExchange/StackExchange.Redis
string value = "abcdefg";await db.StringSetAsync("mykey", value);...string value = await db.StringGetAsync("mykey");Console.WriteLine(value); // writes: "abcdefg"
public async Task SetRecaptchaCache(ConsumerType model) { string recaptchaHashKey = GetRecaptchaHashKey(model); await m_redis.StringSetAsync(recaptchaHashKey, true, TimeSpan.FromMinutes(10)).ConfigureAwait(false); }
![Page 63: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/63.jpg)
MongoDBhttps://github.com/mongodb/mongo-csharp-driver
var client = new MongoClient("mongodb://localhost:27017"); var database = client.GetDatabase("foo"); var collection = database.GetCollection<Person>("bar"); await collection.InsertOneAsync(new Person { Name = "Jack" }); var list = await collection.Find(x => x.Name == "Jack") .ToListAsync(); foreach(var person in list) { Console.WriteLine(person.Name); }
![Page 64: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/64.jpg)
Amazon Web Serviceshttp://docs.aws.amazon.com/sdkfornet/latest/apidocs/Index.html
Simple Notification Service (SNS) public virtual Task<PublishResponse>
PublishAsync( PublishRequest request, CancellationToken cancellationToken )
Simple Queue Service (SQS) public virtual Task<SendMessageResponse>
SendMessageAsync( SendMessageRequest request, CancellationToken cancellationToken)
Simple Storage Service (S3) public virtual Task<GetObjectResponse>
GetObjectAsync( GetObjectRequest request, CancellationToken cancellationToken )
![Page 65: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/65.jpg)
New in .NET 4.6
Not much… Task.FromException Task.FromCancelled Task.CompletedTask Task{Creation/Continuation}Options.RunContinuationsAsynchronously
Allows you to run .SetResult within a lock Except…
Now able to await in catch and finally blocks!
![Page 66: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/66.jpg)
Conclusion
Code the way you live, asynchronously! That is, code NETWORK I/O calls asynchronously
But… Don’t use async on synchronously running code Test the performance. Is it saving time?
![Page 67: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/67.jpg)
Questions?
![Page 68: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/68.jpg)
Why run this as async?
[HttpGet] [Route("geturlasync")] public async Task<string> GetUrlAsync() { string result = await _httpService.GetUrlAsync("http://blogs.msdn.com/b/pfxteam/"); return result; }
There is no thread! When the thread has no more work to do while awaiting, it goes back to the
threadpool Increased server throughput
Server can process more requests
![Page 69: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/69.jpg)
Task.YieldCopied from TAP dochttps://www.microsoft.com/en-us/download/details.aspx?id=19957
Task.Run(async delegate{ for(int i=0; i<1000000; i++) { await Task.Yield(); // fork the continuation into a separate work item ... }});
![Page 70: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/70.jpg)
public static Task<string> DownloadStringAsync(Uri url){ var tcs = new TaskCompletionSource<string>(); var wc = new WebClient(); wc.DownloadStringCompleted += (s,e) => { if (e.Error != null) tcs.TrySetException(e.Error); else if (e.Cancelled) tcs.TrySetCanceled(); else tcs.TrySetResult(e.Result); }; wc.DownloadStringAsync(url); return tcs.Task;}
TaskCompletionSource and EAPCopied from TAP dochttps://www.microsoft.com/en-us/download/details.aspx?id=19957
![Page 71: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/71.jpg)
Meet the experts Stephen Toub
On Visual Studio Parallel Programming team at Microsoft
http://blogs.msdn.com/b/pfxteam/ Wrote THE document on the TAP
https://www.microsoft.com/en-us/download/details.aspx?id=19957
Speaker at MS Build 2011,2013
![Page 72: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/72.jpg)
Meet the experts cont’d Stephen Cleary
Microsoft MVP Avid StackOverflow user
Answered my async/await question
Great blog http://blog.stephencleary.com/
Wrote the book on concurrency
Concurrency in C# Cookbook on Amazon
![Page 73: Async and Await on the Server](https://reader034.vdocument.in/reader034/viewer/2022052308/589e53851a28ab1c7f8b6961/html5/thumbnails/73.jpg)
References The Task-based Asynchronous Pattern The zen of async: Best practices for best performance
MS Build 2011 video – Stephen Toub Async in ASP.NET video with Damian Edwards et al. Async'ing Your Way to a Successful App with .NET
MS Build 2013 video – Stephen Toub Building parallelized apps with .NET and Visual Studio
MS Build 2011 video – Stephen Toub Stephen Toub: Task-Based Asynchrony with Async