Upload
hina
View
46
Download
0
Embed Size (px)
DESCRIPTION
Async’ing Your Way to a Successful App with .NET. Stephen Toub Visual Studio 3-301. Agenda. 6 Tips for Building Better Apps. #1. Wrap Events with Tasks to Improve Control Flow. public async Task RunStoryboardAsync ( this Storyboard sb ) { - PowerPoint PPT Presentation
Citation preview
Async’ing Your Way to a Successful App with .NET
Stephen ToubVisual Studio3-301
6 Tips for Building Better AppsAgenda
Library SupportTaskCompletionSource<T>
Can be used to wrap arbitrary operations as a TaskOnce operations are exposed as Tasks, you can compose over them as you
would any Task
Patternpublic async Task RunStoryboardAsync(this Storyboard sb){ var tcs = new TaskCompletionSource<bool>();
EventHandler<object> handler = (s,e) => tcs.SetResult(true); sb.Completed += handler; sb.Begin();
await tcs.Task; sb.Completed -= handler;}
public Task<T> RunAsync(Func<T> func){ var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(delegate { try { tcs.SetResult(func()); } catch (Exception e) { tcs.SetException(e); } }); return tcs.Task;}
public Task Delay(int milliseconds){ var tcs = new TaskCompletionSource<bool>();
new Timer(_ => tcs.SetResult(true)).Change(milliseconds, -1);
return tcs.Task;}
public async Task WaitForClickAsync(this Button button){ var tcs = new TaskCompletionSource<bool>();
RoutedEventHandler handler = (s,e) => tcs.SetResult(true); button.Click += handler;
await tcs.Task; button.Click -= handler;}
Wrap Events with Tasks to Improve Control Flow
#1
public Task<T> FooAsync(){ var tcs = new TaskCompletionSource<T>();
// schedule something asynchronously // to invoke tcs.Set*
return tcs.Task;}
Awaiting tasks makes it easy to compose sequences or graphs of operations.
Wrapping Events with Tasks to Improve Control Flow
Use Cancellation to Improve ResponsivenessLibrary SupportCancellationToken as a composable cancellation mechanism var cts = new CancellationTokenSource(); SomeMethod(cts.Token); cts.Cancel();
Pattern
#2
public async Task FooAsync(){ … await SomeDotNetAsync(); await SomeWinRTAsync(); …}
public async Task FooAsync(CancellationToken cancellationToken){ … await SomeDotNetAsync(cancellationToken); await SomeWinRTAsync().AsTask(cancellationToken); …}
Responsiveness isn’t just about keeping the UI available for interaction. More broadly, it’s about doing what the user wants when the user wants.
Using Cancellation to Improve Responsiveness
Be Wary of “Async Void”Language Supportasync void, async Task, & async Task<T>
async Task & async Task<T> return handles to the outstanding workasync void is a “fire-and-forget” mechanism
GuidanceUse async void methods only for top-level entry points (e.g. UI event handlers)
(Use and await async Task-returning methods everywhere else)
Avoid passing async lambdas to void-returning delegates(Don’t pass async lambdas to WinRT methods unless you really know what you’re
doing)
#3
Many problems in async code can be traced back to using “async void” incorrectly.
Avoiding “async void”
Use ConfigureAwait for Perf & ResponsivenessSynchronizationContext represents a target for workDispatcherSynchronizationContext (Post: Dispatcher.BeginInvoke)WinRTSynchronizationContext (Post: CoreDispatcher.RunAsync)
Await Behavior
GuidanceUse ConfigureAwait(false) on all awaits in all methods with code that’s context agnostic (which is most libraries)
#4
await task; // force continuation back to the current sync contextawait task.ConfigureAwait(false); // try to continue executing where awaited task completes
Using ConfigureAwait
Use ConfigureAwait(false)
async void button1_Click(…){ await DoWorkAsync();}
async void button1_Click(…){ DoWorkAsync().Wait();}
async Task DoWorkAsync(){ await Task.Run(…); Console.WriteLine("Done task");}
1. DoWorkAsync invoked on UI thread
3. Await captures SynchronizationContext
and hooks up a continuation to run when
task completes
4. UI blocks waiting for DoWorkAsync-returned Task to
complete6. UI thread still blocked waiting for async operation to
complete.Deadlock! .ConfigureAwait(false) avoids
deadlock.
async Task DoWorkAsync(){ await Task.Run(…).ConfigureAwait(false); Console.WriteLine("Done task");}
2. Task.Run schedules work to run on thread
pool
5. Task.Run task completes on pool & invokes continuation which Posts back
to UI thread
Avoiding using the UI thread unless you actually need to.
Using ConfigureAwait for Responsiveness & Perf
Avoid “Sync over Async”, “Async over Sync” in Libraries
#5
What does asynchrony really mean?SynchronousPerform something here and now.I’ll regain control to execute something else when it’s done.
AsynchronousInitiate something here and now.I’ll regain control to execute something else “immediately”.
public static void PausePrintAsync() { ThreadPool.QueueUserWorkItem(_ => PausePrint());}
public static Task PausePrintAsync() { return Task.Run(() => PausePrint());}
public static Task PausePrintAsync() { var tcs = new TaskCompletionSource<bool>(); new Timer(_ => { Console.WriteLine("Hello"); tcs.SetResult(true); }).Change(10000, Timeout.Infinite); return tcs.Task;}
public static async Task PausePrintAsync() { await Task.Delay(10000); Console.WriteLine("Hello");}
Sync vs Async“Pause for 10 seconds, then output 'Hello' to the console.”Synchronous Asynchronous
public static void PausePrint() { var end = DateTime.Now + TimeSpan.FromSeconds(10); while(DateTime.Now < end); Console.WriteLine("Hello");}
public static void PausePrint() { Task t = PausePrintAsync(); t.Wait();}
“async
over sync”
“syncover
async”
Possible responsiveness problems
Possible scalability problems
Avoid “Sync over Async”, “Async over Sync” in LibrariesGuidanceBe honest! Suffix should help caller to understand implementation.Define “FooAsync” iff you’re not thread-bound (with a few notable exceptions).
Don’t just expose FooAsync as “return Task.Run(() => Foo());”Define “Foo” iff you have a faster sync implementation that won’t deadlock.
Don’t just expose Foo as “FooAsync().Wait();”
ExceptionsMethods exposed from .WinMD assembliesOverrides in some class hierarchies
#5
Use Visual Studio’s async toolingVisual Studio 2012: Stepping with AsyncStep InStep OverStep Out
#6
Stepping through your code as if it were synchronous.
Stepping in, over, and out with async
Debugging Async in Visual Studio 2013Visual Studio 2013: Call Stack WindowProvides a “call stack” across async points.
Visual Studio 2013: Tasks WindowSee and navigate from a list all active async operations.
#7
Knowing how you got here and what’s going on
Using the Call Stack and Task Windows with async
Summary
6 Tips for Building Better Apps1. Wrap events with tasks to improve control flow2. Use cancellation to improve responsiveness3. Be wary of “async void”4. Use ConfigureAwait to improve perf &
responsiveness5. Avoid exposing “sync over async” or “async over
sync”6. Use Visual Studio’s async tooling
Questions? Comments?
ResourcesParallel Programming in .NET Blog:http://blogs.msdn.com/pfxteam
Task-based Async Pattern Whitepaperhttp://aka.ms/tap
Evaluate this session
Scan this QR code to evaluate this session and be automatically entered in a drawing to win a prize!
© 2013 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.