Jan 20, 2015
You?
Wikipedia
“Asynchronous events are those occurring independently of the main program flow. Asynchronous actions are actions executed in a non-blocking scheme, allowing the main program flow to continue processing”
You Should Use Async Today
• Your UI always remains responsive• No need to guard against race conditions• No ugly callbacks• Compiler does all the heavy li!ing
Async in C#
• New major feature of C# 5.0Makes asynchronous programming a first-class citizen in C#Important part of C# – as significant as LINQ
• New async modifier keyword introduced• Methods, lambda expressions, and anonymous methods can be
asynchronous• New contextual keyword await introduced
Adding Async to Your Codebase
• Decorated with new async modifier• Async method must return one of
Task, Task<T> or void type
• Async anonymous method and lambdasDelegates returning Task, Task<T> or void
• Very few restrictionsNo ref or out parameters allowedNo unsafe codeNo Main async methodNo async iterators (aka IAsyncEnumerable<T>)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Example: Calculating a Price Asynchronously public async Task<int> CalculatePriceAsync (Item[] items){int price;// Calculate price asynchronously and return the valuereturn price;
}
public override void ViewDidLoad (){button.TouchDown += async (sender, e) => {
// This is asynchronous handler};
}
Await Introduction
• Await can be used in async context onlyMarks a suspension pointCan be used anywhere (except catch and finally blocks)Requires awaitable types (Task, Task<T> but can be any custom type)As many as you like inside async block
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Calculating a Price Asynchronously public async Task<int> CalculatePriceAsync (Item[] items){using (var cmd = CreateSqlCommand (Calculations.TotalPrice, items)) {
using (var reader = await cmd.ExecuteReaderAsync ()) {int price = ReadPrice (reader);return price;
}}
}public override void ViewDidLoad (){button.TouchDown += async (sender, e) => {
var price = await CalculatePriceAsync (items);priceLabel.Text = price.ToString ();
};}
Cancelling an Async Task
• CancellationToken controls cancellation process• Async method needs explicitly support it
Usually another method overloadTask SaveAsync (CancellationToken token)
• Caller calls Cancel on CancellationTokenSourceAsync method stops and returns Task with cancelled stateImplementation detail how quickly async method terminates
DEMO
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Async Language Featurespublic async Task RealAsync (){// This is real async heavy code (only 7 awaits someone else will// certainly do better)var test = new TestClass (await CallAsync () | await CallAsync ()) { Latitude = await GetLatitudeAsync (await AnotherAsync ()), Roles = from role in await GetRolesAsync ()
where role == "agent" select role};....test [await CallAsync ()] = new int[] { 33, await GetIntAsync () };...
}
Best Practices
• Use Async naming suffix for asynchronous methodsLoadAsync, SendAsync, etc.Only recommended naming convention
• Return Task or Task<T> preferablyTask for SaveAsync like methodsTask<T> for ReadAsync like methodsLeave async void to event handlers only
• Support cancellation, if possible
Synchronization Context
• Framework abstraction over UI toolkit threading modelNSRunLoop, DispatchContext in Xamarin.iOSMainLooper in Xamarin.AndroidDispatcher in WPFetc.
• Await uses synchronization context to restore back suspended context
SynchronizationContext::Post method is usedSuspension on UI thread resumes back on same UI thread as “expected”
Sometimes Things Go Wrong
• Async returning Task or Task<T>Task state is set to FaultedException is re-thrown when Task is checked (awaited)
• Async voidFire and forget asynchronyException is thrown on current synchronization context and your app will crash
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Exception Handling with Awaitpublic override void ViewDidLoad (){button.TouchDown += async (sender, e) => {
try {button.Enabled = false;var price = await CalculatePriceAsync (items);priceLabel.Text = price.ToString ();
} catch (Exception ex) {// Handles price calculation errorpriceLabel.Text = "Calculation failed";Debug.Print (ex.ToString ()); // Simple exception logging
} finally {button.Enabled = true;
}};
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Exception Throwingpublic async Task<int> CalculatePriceAsync (Item[] items){if (items == null) {
// Throw before suspensionthrow new ArgumentNullException ("items");
}...var price = await CalculatePriceAsync (items);if (price < 0) {
// Throw after suspensionthrow new ArgumentException ("Invalid items");
}...
}
Diving Deeper
• Await can work with any type which implements the awaiter pattern
• Task and Task<T> types do since .NET 4.5• Any custom type can be made awaitable
Has an accessible method called GetAwaiter returning a type whichImplements the interface INotifyCompletionHas property IsCompleted of type boolHas method GetResult with no parameters
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Custom await Behaviourpublic async Task<int> SomeAsync (){ ... await 3000; // This does not compile unless we provide custom awaiter ...}
// Name of the method is importantstatic TaskAwaiter GetAwaiter (this int millisecondsDelay){ return Task.Delay (millisecondsDelay).GetAwaiter ();}
Async Deadlocks
• await restores execution context based on current SynchronizationContext
Good for most application codeBad for most library code
• Don’t block the UI threadGood old rule still applies in async worldUse await when possible
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Async Deadlock Examplepublic async Task<int> CalculatePriceAsync (Item[] items){using (var cmd = CreateSqlCommand (Calculations.TotalPrice, items)) {
using (var r = await cmd.ExecuteReaderAsync ()) {.....
}}
}
// The method itself cannot be asyncpublic override bool FinishedLaunching (UIApplication app, NSDictionary options){....int price = CalculatePriceAsync (items).Result; // Synchronous wait// This line won’t be reached if flow suspension occurred
}
Controlling the Synchronization Context
• ConfigureAwait (bool)Controls captured context behaviour
• true value - default behaviourContinue execution on context async was called fromImportant for UI to switch back to UI context
• false valueAvoids expensive context switchingAvoids possible deadlocks on blocking UI
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
Async Deadlock Fixedpublic async Task<int> CalculatePriceAsync (Item[] items){using (var cmd = CreateSqlCommand (Calculations.TotalPrice, items)) {using (var r = await cmd.ExecuteReaderAsync ().ConfigureAwait (false)) {// The context is not restored but that’s fine for no UI method
}}
}
// The method itself cannot be asyncpublic override bool FinishedLaunching (UIApplication app, NSDictionary options){....int price = CalculatePriceAsync (items).Result; // Synchronous wait// Program continues when the wait is signalled
}
Combinators
• Asynchronously wait on multiple asynchronous operationsBetter than individual awaits of multiple tasksThe result can be awaited (Task of Tasks)
• Task.WhenAll (IEnumerable<Task>)Completes when all of the individual tasks have completed
• Task.WhenAny (IEnumerable<Task>)Completes when any of the individual tasks have completed
The Compiler Magic
• Compiler does all the “magic”• Local variable and parameters are li!ed into compiler generated
typeCompiler converts variables and parameters to fields
• Any stack values need to be li!ed tooStack needs to be restored a"er suspension
• Try-Catch block over any async block• No suspension when awaited task finished
Best Practices - Performance
• Use ConfigureAwait when you can• Reduce number of local variables
Move async block into separate method or lambda expressionPass variables as parametersAvoid deep await usage
• Cache Task not task result• Don’t over use async
Use async only when appropriate (unreliable tasks, running >50ms)Async has its own overhead
Get Your Hands on Async
• Async is available todayXamarin.iOS Beta releaseXamarin.Android Beta releaseXamarin Studio async support
• Give us feedback on our new async APIForumsBugzillaMailing listIRC
Q&A
THANK YOU