Lisbon, May 30th 2015
await Xamarin()PTXug - Xamarin Talks #1
Speaker
http://PauloMorgado.NET/http://about.me/PauloMorgadohttp://www.slideshare.net/PauloJorgeMorgadohttp://pontonetpt.org/blogs/paulomorgado/http://blogs.msmvps.com/paulomorgado/http://weblogs.asp.net/paulomorgadohttp://www.revista-programar.info/author/pmorgado/
C:\> ping me @paulomorgado
async-await best practices
Agenda
For goodness’ sake, stop using async void!
async void is only for event handlers
PrinciplesAsync void is a “fire-and-forget” mechanism...The caller is unable to know when an async void has finishedThe caller is unable to catch exceptions thrown from an async void
(instead they get posted to the UI message-loop)
GuidanceUse async void methods only for top-level event handlers (and their like)Use async Task-returning methods everywhere elseIf you need fire-and-forget elsewhere, indicate it explicitly e.g. “FredAsync().FireAndForget()”When you see an async lambda, verify it
Events are not going away.
async over events
PrinciplesCallback-based programming, as with events, is hard
GuidanceIf the event-handlers are largely independent, then leave them as eventsBut if they look like a state-machine, then await is sometimes easierTo turn events into awaitable Tasks, use TaskCompletionSource
Is it CPU-bound,or I/O-bound?
Thread pool
PrinciplesCPU-bound work means things like: LINQ-over-objects, or big iterations, or computational inner loops.Parallel.ForEach and Task.Run are a good way to put CPU-bound work onto the thread pool.Thread pool will gradually feel out how many threads are needed to make best progress.Use of threads will never increase throughput on a machine that’s under load.
GuidanceFor IO-bound “work”, use await rather than background threads.For CPU-bound work, consider using background threads via Parallel.ForEach or Task.Run, unless you're writing a library, or scalable server-side code.
Don’t lie
Two ways of thinking about asynchrony
Foo();Perform something here and now.I’ll regain control to execute something else when it’s done.
var task = FooAsync();Initiate something here and now.I’ll regain control to execute something else “immediately”.
From the method signature (how people call it)
Uses a CPU core solidly while it runs
void Foo(){ for (int i=0; i<100; i++) Math.Sin(i);}
From the method implementation (what resources it uses) Hardly touches the CPU
async Task FooAsync(){ await client.DownloadAsync();}
Async methods: Your caller’s assumptions
“This method’s name ends with ‘Async’, so…”
“…calling it won’t spawn new threads in my server app”
“…I can parallelize by simply calling it multiple times”
Is this true for your async methods?
Libraries shouldn’t use Task.Run()
Your callers should be the ones to call Task.Run
The thread pool is an app-global resourceThe number of threads available to service work items varies greatly over the life of an appThe thread pool adds and removes threads using a hill climbing algorithm that adjusts slowly
In a server app, spinning up threads hurts scalability
A high-traffic server app may choose to optimize for scalability over latencyAn API that launches new threads unexpectedly can cause hard-to-diagnose scalability bottlenecks
The app is in the best position to manage its threads
Provide synchronous methods that block the current threadProvide asynchronous methods when you can do so without spawning new threadsLet the app that called you use its domain knowledge to manage its threading strategy!
Sync methods: Your caller’s assumptions
“There’s a synchronous version of this method…”
“…I guess it must be faster than the async version”
“…I can call it from the UI thread if the latency’s fine”
void Foo() { FooAsync().Wait(); } -- will deadlock!!!
Task.Run() is the way to create new tasks
Task creation
PrinciplesTask.Run returns hot tasks (running or completed) created with settings suited to async-await.
GuidanceDon’t use Task.Factory.StartNew or the Task (or Task<T>) constructor.
await all the way
await all the way
PrinciplesThe compiler provides, through the await keyword, sequential execution of the code.
GuidanceDon’t mix async-await with ContinuesWith.
Use ConfigureAwait(fals
e)
SynchronizationContext
Represents a target for work via its Post methodWindowsFormsSynchronizationContext
.Post() does Control.BeginInvoke
DispatcherSynchronizationContext.Post() does Dispatcher.BeginInvoke
AspNetSynchronizationContext.Post() ensures one-at-a-time
… // ~10 in .NET Framework, and you can write your own… // Is the core way for “await” to know how to put you back
SynchronizationContext and await
“await task;”Captures the current SyncContext before awaiting.When it resumes, uses SyncContext.Post() to resume “in the same place”(If SyncContext is null, uses the TaskScheduler)
For application-level code:This behavior is almost always what you want.
For library-level code:This behavior is rarely what you want!
SynchronizationContext: ConfigureAwait
Task.ConfigureAwait(bool continueOnCapturedContext)
await t.ConfigureAwait(true) // defaultPost continuation back to the current context/scheduler
await t.ConfigureAwait(false)If possible, continue executing where awaited task completes
ImplicationsPerformance (avoids unnecessary thread marshaling)Deadlock (code shouldn’t block UI thread, but avoids deadlocks if it does)
Use the CancellationToken
Use the CancellationToken
PrinciplesThe CancellationToken structure is the way to signal and handle cancellation.
GuidanceIf you want your API to be cancellable, use cancellation tokens.If your code uses APIs that use cancellation tokens, use them.Always check the cancellation tokens.
Cache the returned Task<T>
Library perf considerations
PrinciplesAsync methods are faster than what you could write manually, but still slower than synchronous.The chief cost is in memory allocation (actually, in garbage collection).The "fast path" bypasses some allocations.
GuidanceAvoid designing "chatty" APIs where async methods are called in an inner loop; make them "chunky".If necessary, cache the returned Task object (even with cache size "1"), for zero allocations per call.As always, don't prematurely optimize!
Q & A
References
Talk: Async best practiceshttp://blogs.msdn.com/b/lucian/archive/2013/11/23/talk-mvp-summit-async-best-practices.aspx
Six Essential Tips For Async – Introductionhttp://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Three-Essential-Tips-For-Async-Introduction
Curah! async-await Generalhttp://curah.microsoft.com/45553/asyncawait-general
Curah! async-await and ASP.NEThttp://curah.microsoft.com/44400/async-and-aspnet
Xamarin Store Apphttps://github.com/paulomorgado/xamarin-xamarin-store-app
Sponsors
THANK YOU !C:\> ping me
@paulomorgado