Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Abusing Async/Await (for fun and profit)

Abusing Async/Await (for fun and profit)

async/await was the hottest feature of C# 6 when it came out, bringing a radically improved way to write asynchronous code and cure us of callback hell. But how does it really work?

In this talk we will take a deeper look at the machinery behind async/await and take advantage of the lesser known tuning capabilities introduced with C# 7 to use async/await in ways you wouldn’t have thought of like re-implementing F# computation expressions and supporting mobile patterns on Android.

Jérémie Laval

October 24, 2017
Tweet

More Decks by Jérémie Laval

Other Decks in Technology

Transcript

  1. Async fact sheet • C# 6 (circa 2015) • Based

    on TPL’s Task primitive • State-machine compiler trickery (like yield) • A fancy way to chain callbacks
  2. http://callbackhell.com/ fs.readdir(source, function (err, files) { if (err) { console.log('Error

    finding files: ' + err) } else { files.forEach(function (filename, fileIndex) { console.log(filename) gm(source + filename).size(function (err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function (width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } })
  3. Awaitable/Awaiter • Simpler abstractions than plain Task • Same concept

    as IEnumerable/IEnumerator • Convention based!
  4. Awaitable Conventions interface IAwaitable { IAwaiter GetAwaiter (); } //

    Or struct StructAwaitable { IAwaiter GetAwaiter (); } // Or public static class Extensions { public static IAwaiter GetAwaiter (this MyClass self); }
  5. Awaiter interface IAwaiter : INotifyCompletion { bool IsCompleted { get;

    } void OnCompleted (Action action); void GetResult (); // Or OtherType GetResult (); }
  6. Async functions A method or anonymous function with the async

    modi3ier is called an async function. In general, the term async is used to describe any kind of function that has the async modi3ier. The return_type of an async method must be either void or a task type. The task types are System.Threading.Tasks.Task and types constructed from System.Threading.Tasks.Task<T> C#6
  7. Async rewriting class MainClass
 {
 public static async Task Main

    (string[] args)
 {
 Console.WriteLine ("Hello");
 await Task.Delay (200);
 Console.WriteLine ("World");
 }
 } [AsyncStateMachine (typeof(MainClass.<Main>d__0))]
 public static Task Main (string[] args)
 {
 MainClass.<Main>d__0 <Main>d__ = new MainClass.<Main>d__0 ();
 <Main>d__.args = args;
 <Main>d__.<>t__builder = AsyncTaskMethodBuilder.Create ();
 <Main>d__.<>1__state = -1;
 AsyncTaskMethodBuilder <>t__builder = <Main>d__.<>t__builder;
 <>t__builder.Start<MainClass.<Main>d__0> (ref <Main>d__);
 return <Main>d__.<>t__builder.Task;
 } [AsyncStateMachine (typeof(AutoGeneratedStateMachine))]
 public static Task Main (string[] args)
 {
 AutoGeneratedStateMachine stateMachine = new AutoGeneratedStateMachine ();
 stateMachine.args = args;
 stateMachine.builder = AsyncTaskMethodBuilder.Create ();
 stateMachine.state = -1;
 AsyncTaskMethodBuilder builder = stateMachine.builder;
 builder.Start<AutoGeneratedStateMachine> (ref stateMachine);
 return stateMachine.builder.Task;
 }
  8. Custom Awaiters • Tasks have their own TaskAwaiter • Task.Yield()

    is a custom awaiter
 • Represent any form of async operations • … Or not! public static System.Runtime.CompilerServices.YieldAwaitable Yield ();
  9. The story of an optimization interface IAwaiter : INotifyCompletion {

    bool IsCompleted { get; } void OnCompleted (Action action); void GetResult (); // Or OtherType GetResult (); }
  10. Midori Joe Duffy The 3irst key optimization, therefore, is that

    an async method that doesn’t await shouldn’t allocate anything. We were able to share this experience with .NET in time for C#’s await to ship. http://joeduffyblog.com/2015/11/19/asynchronous-everything/
  11. var awaiter = /*awaitable*/.GetAwaiter (); if (!awaiter.IsCompleted) { // Indirectly

    call awaiter.OnCompleted this.builder.AwaitOnCompleted (/**/); return; } Allocations in there usually
  12. Async functions A method or anonymous function with the async

    modi3ier is called an async function. In general, the term async is used to describe any kind of function that has the async modi3ier. The return_type of an async method must be either void or a task type. The task types are System.Threading.Tasks.Task and types constructed from System.Threading.Tasks.Task<T> C#6
  13. ValueTask async Task<int> Get404IntegerAsync () { if (conditionThatsAlmostAlwaysTrue) return 404;

    return await Expensive404Async (); } Reference type Value type Allocation
  14. ActivityTask • async/await totally supported by Xamarin.Android • Async needs

    to understand Android lifecycle • Problem 1: Android Activity survival not guaranteed! • Problem 2: Activity are pausable/freezable! https://blog.neteril.org/blog/2017/05/22/activitytask-async-await-android-cornercases/
  15. F# computation expression let divideBy bottom top = if bottom

    = 0 then None else Some(top/bottom) type MaybeBuilder() = member this.Bind(m, f) = Option.bind f m member this.Return(x) = Some x let maybe = new MaybeBuilder() let divideByWorkflow x y w z = maybe { let! a = x |> divideBy y let! b = a |> divideBy w let! c = b |> divideBy z return c } // test let good = divideByWorkflow 12 3 2 1 let bad = divideByWorkflow 12 3 0 1 https://fsharpforfunandprofit.com/series/computation-expressions.html
  16. Take-away C# async/await is a generic facility to create chainable

    continuations and apply cool stuff in-between