Your SlideShare is downloading. ×
0
WHO WILL BENEFIT FROM THIS                                          TOPICS                             WHAT YOU’LL LEAVE W...
public static void SimpleBody() {  Console.WriteLine("Hello, Async World!");}.method public hidebysig static void SimpleBo...
.method public hidebysig instance void MoveNext() cil managed                                     {                       ...
Demo Async methods
[CompilerGenerated]private class <SimpleBody>d__0{    private int <>1__state;    public AsyncTaskMethodBuilder <>t__builde...
TResult result = await FooAsync();   var $awaiter = FooAsync().GetAwaiter();                                     if (!$awa...
public async Task FooAsync()   public async Task<bool> FooAsync()   public async Task<object> FooAsync(){                 ...
public override async Task<int> ReadAsync(    byte [] buffer, int offset, int count, CancellationToken cancellationToken){...
private Task<int> m_lastTask;public override Task<int> ReadAsync(  byte [] buffer, int offset, int count,  CancellationTok...
Demo Manually caching tasks based on domain knowledge leads to improved performance.
private static ConcurrentDictionary<string,string> s_urlToContents;public static async Task<string> GetContentsAsync(strin...
private static ConcurrentDictionary<string,Task<string>> s_urlToContents;public static Task<string> GetContentsAsync(strin...
Demo Cache Task<TResult> instead of TResult to avoid unnecessary Task allocations.
Demo
User’s app                                              Your library       async void button1_Click(…)                    ...
Demo Library implementers should use ConfigureAwait(false) to improve performance and to help avoid deadlocks.
Demo Modifying ExecutionContext sabotages built-in optimizations.
public static async Task FooAsync() {     [CompilerGenerated, StructLayout(LayoutKind.Sequential)]  var dto = DateTimeOffs...
Demo Async method “locals” become fields on a heap- allocated class. More locals => more fields => bigger
Async methods are not ordinarymethods.Use them!But avoid fine-grained async.
Cache tasks when applicable.Use ConfigureAwait(false) in libraries.Avoid gratuitous use of ExecutionContext.Remove unneces...
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
The zen of async: Best practices for best performance
Upcoming SlideShare
Loading in...5
×

The zen of async: Best practices for best performance

1,886

Published on

More info on http://www.techdays.be

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,886
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
42
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "The zen of async: Best practices for best performance"

  1. 1. WHO WILL BENEFIT FROM THIS TOPICS WHAT YOU’LL LEAVE WITH TALK• .NET library developers : • Getting the Right Mental Model • Knowledge of: • with knowledge of • Knowing When Not To Use Async • when to care about async/await in C# / VB optimizing your async • Avoiding Allocations implementations • interested in low-level perf • Caring About Context • …and how to do it • that understand this is based on the Developer • Minimizing Suspensions Preview
  2. 2. public static void SimpleBody() { Console.WriteLine("Hello, Async World!");}.method public hidebysig static void SimpleBody() cil managed{ .maxstack 8 L_0000: ldstr "Hello, Async World!" L_0005: call void [mscorlib]System.Console::WriteLine(string) L_000a: ret}
  3. 3. .method public hidebysig instance void MoveNext() cil managed { // Code size 66 (0x42) .maxstack 2 .locals init ([0] bool <>t__doFinallyBodies, [1] class [mscorlib]System.Exception <>t__ex) .try { IL_0000: ldc.i4.1 IL_0001: stloc.0 IL_0002: ldarg.0 IL_0003: ldfld int32 Program/<SimpleBody>d__0::<>1__statepublic static async Task SimpleBody() { IL_0008: ldc.i4.m1 Console.WriteLine("Hello, Async World!"); IL_000d IL_0009: bne.un.s IL_000b: leave.s IL_0041} IL_000d: ldstr "Hello, Async World!" IL_0012: call void [mscorlib]System.Console::WriteLine(string) IL_0017: leave.s IL_002f.method public hidebysig static class [mscorlib]System.Threading.Tasks.Task SimpleBody() cil managed }{ catch [mscorlib]System.Exception .custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = ( 01 00 00 00 ) { // Code size 32 (0x20) IL_0019: stloc.1 .maxstack 2 IL_001a: ldarg.0 .locals init ([0] valuetype Program/<SimpleBody>d__0 V_0) IL_001b: ldc.i4.m1 IL_0000: ldloca.s V_0 IL_001c: stfld int32 Program/<SimpleBody>d__0::<>1__state IL_0002: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder IL_0021: ldarg.0 [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Create() IL_0022: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder IL_0007: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program/<SimpleBody>d__0::<>t__builder Program/<SimpleBody>d__0::<>t__builder IL_000c: ldloca.s V_0 IL_0027: ldloc.1 IL_000e: call instance void Program/<SimpleBody>d__0::MoveNext() [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetException( IL_0028: call instance void IL_0013: ldloca.s V_0 class [mscorlib]System.Exception) IL_0015: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program/<SimpleBody>d__0::<>t__builder IL_002d: leave.s IL_0041 IL_001a: call instance class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::get_Task() } IL_001f: ret IL_002f: ldarg.0} IL_0030: ldc.i4.m1 IL_0031: stfld int32 Program/<SimpleBody>d__0::<>1__state IL_0036: ldarg.0 IL_0037: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program/<SimpleBody>d__0::<>t__builder IL_003c: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::SetResult() IL_0041: ret }
  4. 4. Demo Async methods
  5. 5. [CompilerGenerated]private class <SimpleBody>d__0{ private int <>1__state; public AsyncTaskMethodBuilder <>t__builder; public Action <>t__MoveNextDelegate; public void MoveNext();}<>t__awaiter1.OnCompleted(<>t__MoveNextDelegate);public static Task SimpleBodyAsync() { ... d__.<>t__builder = AsyncTaskMethodBuilder.Create(); ... return d__.<>t__builder.Task;}
  6. 6. TResult result = await FooAsync(); var $awaiter = FooAsync().GetAwaiter(); if (!$awaiter.IsCompleted) { SAVE_STATE; $awaiter.OnCompleted(CompletionDelegate); return; Label: RESTORE_STATE; } TResult result = $awaiter.GetResult();
  7. 7. public async Task FooAsync() public async Task<bool> FooAsync() public async Task<object> FooAsync(){ { { ... // doesn’t yield ... // doesn’t yield ... // doesn’t yield return; return true; return null;} } }
  8. 8. public override async Task<int> ReadAsync( byte [] buffer, int offset, int count, CancellationToken cancellationToken){ cancellationToken.ThrowIfCancellationRequested(); return Read(buffer, offset, count);}public static async Task CopyStreamAsync(Stream input, Stream output){ var buffer = new byte[0x1000]; int numRead; while((numRead = await input.ReadAsync(buffer, 0, buffer.Length)) > 0) { await output.WriteAsync(buffer, 0, numRead); }}
  9. 9. private Task<int> m_lastTask;public override Task<int> ReadAsync( byte [] buffer, int offset, int count, CancellationToken cancellationToken){ if (cancellationToken.IsCancellationRequested) { var tcs = new TaskCompletionSource<int>(); tcs.SetCanceled(); return tcs.Task; } try { int numRead = this.Read(buffer, offset, count); return m_lastTask != null && numRead == m_lastTask.Result ? m_lastTask : (m_lastTask = Task.FromResult(numRead)); } catch(Exception e) { var tcs = new TaskCompletionSource<int>(); tcs.SetException(e); return tcs.Task; }}
  10. 10. Demo Manually caching tasks based on domain knowledge leads to improved performance.
  11. 11. private static ConcurrentDictionary<string,string> s_urlToContents;public static async Task<string> GetContentsAsync(string url){ string contents; if (!s_urlToContents.TryGetValue(url, out contents)) { var response = await new HttpClient().GetAsync(url); contents = response.EnsureSuccessStatusCode().Content.ReadAsString(); s_urlToContents.TryAdd(url, contents); } return contents;}
  12. 12. private static ConcurrentDictionary<string,Task<string>> s_urlToContents;public static Task<string> GetContentsAsync(string url){ Task<string> contents; if (!s_urlToContents.TryGetValue(url, out contents)) { contents = GetContentsAsyncInternal(url); contents.ContinueWith(t => s_urlToContents.TryAdd(url, t); }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuatOptions.ExecuteSynchronously, TaskScheduler.Default); } return contents;}private static async Task<string> GetContentsAsyncInternal(string url) { var response = await new HttpClient().GetAsync(url); return response.EnsureSuccessStatusCode().Content.ReadAsString();}
  13. 13. Demo Cache Task<TResult> instead of TResult to avoid unnecessary Task allocations.
  14. 14. Demo
  15. 15. User’s app Your library async void button1_Click(…) async Task DoWorkAsync() { { DoWorkAsync().Wait(); await DoWorkAsync(); await Task.Run(…); Task.Run(…).ConfigureAwait(false); } Console.WriteLine("Done task"); } 3. Await captures 1. DoWorkAsync 2. Task.Run schedules work SynchronizationContext andinvoked on UI thread to run on thread pool 4. UI blocks waiting for hooks up a continuation to run DoWorkAsync-returned when task completes Task to complete 5. Task.Run task completes on pool & invokes 6. UI thread still blocked continuation which Posts back to UI thread waiting for async operation to complete. Deadlock! .ConfigureAwait(false) avoids deadlock.
  16. 16. Demo Library implementers should use ConfigureAwait(false) to improve performance and to help avoid deadlocks.
  17. 17. Demo Modifying ExecutionContext sabotages built-in optimizations.
  18. 18. public static async Task FooAsync() { [CompilerGenerated, StructLayout(LayoutKind.Sequential)] var dto = DateTimeOffset.Now; private struct <FooAsync>d__0 : <>t__IStateMachine { var dt = dto.DateTime; public DateTimeOffset <dto>5__1; await Task.Delay(1000); public DateTime <dt>5__2; Console.WriteLine(dt); ...} }public static async Task FooAsync() { [CompilerGenerated, StructLayout(LayoutKind.Sequential)] var dt = DateTimeOffset.Now.DateTime; private struct <FooAsync>d__0 : <>t__IStateMachine { await Task.Delay(1000); public DateTime <dt>5__2; Console.WriteLine(dt); ...} }
  19. 19. Demo Async method “locals” become fields on a heap- allocated class. More locals => more fields => bigger
  20. 20. Async methods are not ordinarymethods.Use them!But avoid fine-grained async.
  21. 21. Cache tasks when applicable.Use ConfigureAwait(false) in libraries.Avoid gratuitous use of ExecutionContext.Remove unnecessary locals.
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×