Async void is only for toplevel event handlers

  • Slides: 61
Download presentation

Async void is only for top-level event handlers. Use Task. Completion. Source to wrap

Async void is only for top-level event handlers. Use Task. Completion. Source to wrap Tasks around events. Use threadpool for CPU-bound code, but not IO-bound, Libraries shouldn't lie, should use Configure. Await, should be chunky.

Message pump Click async void Button 1_Click(){ await Load. Settings. Async(); Update. View(); Task.

Message pump Click async void Button 1_Click(){ await Load. Settings. Async(); Update. View(); Task. . . Load. Settings async Task Load. Settings. Async() { Load. Settings. Async } await IO. Network. Download. Async(path); } Task. . . Download. Async Click

private async void Button 1_Click(object Sender, Event. Args e) { try { Send. Data("https:

private async void Button 1_Click(object Sender, Event. Args e) { try { Send. Data("https: //secure. flickr. com/services/oauth/request_token"); await Task. Delay(2000); Debug. Print("Received Data: " + m_Get. Response); } catch (Exception ex) { root. Page. Notify. User("Error posting data to server. " + ex. Message); } } private async void Send. Data(string Url) { var request = Web. Request. Create(Url); using (var response = await request. Get. Response. Async()) using (var stream = new Stream. Reader(response. Get. Response. Stream())) m_Get. Response = stream. Read. To. End(); }

private async void Button 1_Click(object Sender, Event. Args e) { try { Send. Data("https:

private async void Button 1_Click(object Sender, Event. Args e) { try { Send. Data("https: //secure. flickr. com/services/oauth/request_token"); // await Task. Delay(2000); // Debug. Print("Received Data: " + m_Get. Response); } catch (Exception ex) { root. Page. Notify. User("Error posting data to server. " + ex. Message); } } private async void Send. Data(string Url) { var request = Web. Request. Create(Url); using (var response = await request. Get. Response. Async()) // exception on resumption using (var stream = new Stream. Reader(response. Get. Response. Stream())) m_Get. Response = stream. Read. To. End(); }

private async void Button 1_Click(object Sender, Event. Args e) { try { Async await

private async void Button 1_Click(object Sender, Event. Args e) { try { Async await Send. Data("https: //secure. flickr. com/services/oauth/request_token"); await Task. Delay(2000); Debug. Print("Received Data: " + m_Get. Response); } catch (Exception ex) { root. Page. Notify. User("Error posting data to server. " + ex. Message); } } Task Async private async void Send. Data(string Url) { var request = Web. Request. Create(Url); using (var response = await request. Get. Response. Async()) using (var stream = new Stream. Reader(response. Get. Response. Stream())) m_Get. Response = stream. Read. To. End(); }

// Q. It sometimes shows Pixel. Width and Pixel. Height are both 0 ?

// Q. It sometimes shows Pixel. Width and Pixel. Height are both 0 ? ? ? Bitmap. Image m_bmp; protected override async void On. Navigated. To(Navigation. Event. Args e) { base. On. Navigated. To(e); await Play. Intro. Sound. Async(); class Layout. Aware. Page : Page image 1. Source = m_bmp; { Canvas. Set. Left(image 1, Window. Current. Bounds. Width private string _page. Key; - m_bmp. Pixel. Width); } protected override void On. Navigated. To(Navigation. Event. Args e) protected override async void Load. State(Object nav, Dictionary<String, Object> page. State) { { m_bmp = new Bitmap. Image(); if (this. _page. Key != null) return; var file = await Storage. File. Get. File. From. Application. Uri. Async("ms-appx: ///pic. png"); this. _page. Key = "Page-" + this. Frame. Back. Stack. Depth; using (var stream = await file. Open. Read. Async()) {. . . await m_bmp. Set. Source. Async(stream); this. Load. State(e. Parameter, null); } }

// A. Use a task Task<Bitmap. Image> m_bmp. Task; protected override async void On.

// A. Use a task Task<Bitmap. Image> m_bmp. Task; protected override async void On. Navigated. To(Navigation. Event. Args e) { base. On. Navigated. To(e); await Play. Intro. Sound. Async(); var bmp = await m_bmp. Task; image 1. Source = bmp; Canvas. Set. Left(image 1, Window. Current. Bounds. Width - bmp. Pixel. Width); } protected override void Load. State(Object nav, Dictionary<String, Object> page. State) { m_bmp. Task = Load. Bitmap. Async(); } private async Task<Bitmap. Image> Load. Bitmap. Async() { var bmp = new Bitmap. Image(); . . . return bmp; }

// In. VB, C#, theexpression context determines whether async is void- or (not Task-returning.

// In. VB, C#, theexpression context determines whether async is void- or (not Task-returning. ' In itself determines void-lambda or Task-returning the context). Action a 1 = async () =>Sub() { await Load. Async(); m_Result="done"; }; Dim void_returning = Async Func<Task> a 2 = async () => { await Load. Async(); m_Result="done"; }; Await Load. Async() : m_Result = "done" End Sub // Which one will pick? Dim. Q. task_returning = it Async Function() await Task. Run( async () => { await Load. Async(); m_Result="done"; }); Await Load. Async() : m_Result = "done" End Function // A. If both overloads are offered, it will pick Task-returning. Good! class Taskoverloads are offered, you must give it Task-returning. ' If both { Await Task. Run(Async Function(). . . End Function) static public Task Run(Action a) {. . . } static public Task Run(Func<Task> a) {. . . }

try { await Dispatcher. Run. Async(Core. Dispatcher. Priority. Normal, async () => { await

try { await Dispatcher. Run. Async(Core. Dispatcher. Priority. Normal, async () => { await Load. Async(); m_Result = "done"; throw new Exception(); }); } catch (Exception ex) { } finally { Debug. Print(m_Result); } // IAsync. Action Run. Async(Core. Dispatcher. Priority priority, Dispatched. Handler agile. Callback); // delegate void Dispatched. Handler();

Protected Overrides Sub On. Pointer. Pressed(e As Pointer. Routed. Event. Args) Dim apple =

Protected Overrides Sub On. Pointer. Pressed(e As Pointer. Routed. Event. Args) Dim apple = CType(e. Original. Source, Image) Add. Handler apple. Pointer. Released, Sub(s, e 2) Dim endpt = e 2. Get. Current. Point(Nothing). Position If Not Basket. Catchment. Area. Bounds. Contains(endpt) Then Return Canvas. Set. ZIndex(apple, 1) ' mark apple as no longer free If Free. Apples. Count > 0 Then m_Action. After. Animation = Sub() Whoosh. Sound. Stop() Show. Victory. Window() Add. Handler btn. Ok. Click, Sub(). . End Sub End If Whoosh. Sound. Play() Animate. Then. Do. Action(Apple. Into. Basket. Storyboard)

Protected Async Sub On. Pointer. Pressed(e As Pointer. Routed. Event. Args) ' Let user

Protected Async Sub On. Pointer. Pressed(e As Pointer. Routed. Event. Args) ' Let user drag the apple Dim apple = CType(e. Original. Source, Image) Dim endpt = Await Drag. Async(apple) If Not Basket. Catchment. Area. Bounds. Contains(endpt) Then Return ' Animate and sound for apple to whoosh into basket Dim animate. Task = Apple. Storyboard. Play. Async() Dim sound. Task = Whoosh. Sound. Play. Async() Await Task. When. All(animate. Task, sound. Task) If Free. Apples. Count = 0 Then Return ' Show victory screen, and wait for user to click button Await Start. Victory. Screen. Async() Await btn. Play. Again. When. Clicked() On. Start() End Sub

' Await storyboard 1. Play. Async(); storyboard 1. Play. Async() // Usage: await <Extension>

' Await storyboard 1. Play. Async(); storyboard 1. Play. Async() // Usage: await <Extension> Async Function Play. Async(sb As Animation. Storyboard) As Task public static async Task Play. Async(this Storyboard storyboard) { Dim Asnew New. Task. Completion. Source<object>(); Task. Completion. Source(Of Object) var tcs = Dim lambda As Event. Handler(Of Object) Sub() tcs. Try. Set. Result(Nothing) Event. Handler<object> lambda = (s, e) =>=tcs. Try. Set. Result(null); Try try { Add. Handler sb. Completed, lambda storyboard. Completed += lambda; sb. Begin() storyboard. Begin(); Await await tcs. Task; Finally } Remove. Handler sb. Completed, lambda finally { End storyboard. Completed Try -= lambda; End } Function }

// Usage: await button 1. When. Clicked(); public static async Task When. Clicked(this Button

// Usage: await button 1. When. Clicked(); public static async Task When. Clicked(this Button button) { var tcs = new Task. Completion. Source<object>(); Routed. Event. Handler lambda = (s, e) => tcs. Try. Set. Result(null); try { button. Click += lambda; await tcs. Task; } finally { button. Click -= lambda; } }

request in // table 1. Data. Source = Load. Houses. Sequentially(1, 5); work 1

request in // table 1. Data. Source = Load. Houses. Sequentially(1, 5); work 1 // table 1. Data. Bind(); public List<House> Load. Houses. Sequentially(int first, int last) { work 2 var loaded. Houses = new List<House>(); for (int i = first; i <= last; i++) { work 3 House house = House. Deserialize(i); loaded. Houses. Add(house); } work 4 return loaded. Houses; } t ou e s on s p s e r 500 m work 5

request in // table 1. Data. Source = Load. Houses. In. Parallel(1, 5); Parallel.

request in // table 1. Data. Source = Load. Houses. In. Parallel(1, 5); Parallel. For // table 1. Data. Bind(); public List<House> Load. Houses. In. Parallel(int first, int last) { work 1 work 2 var loaded. Houses = new Blocking. Collection<House>(); 4 1 2 Parallel. For(first, last+1, i => { work 3 House house = House. Deserialize(i); loaded. Houses. Add(house); }); 5 3 return loaded. Houses. To. List(); work 5 } response out 300 ms work 4

request in start 1 end 1 start 2 end 2 start 3 end 3

request in start 1 end 1 start 2 end 2 start 3 end 3 start 4 end 4 t ou e s on s p s e r 500 m start 5 end 5

request in sta 1 t 2 2 nd 2 d 1 start 2 end

request in sta 1 t 2 2 nd 2 d 1 start 2 end 1 end 2 start 5 4 sta rt 4 e en d 4 en star rt 1 Parallel. For star 5 end 5 t 5 start 3 3 end 5 end 3 response out ~200 ms start 3 end 3 start 4 end 4

request in start 1 start 2 start 3 start 4 start 5 end 2

request in start 1 start 2 start 3 start 4 start 5 end 2 end 5 end 1 end 3 end 4 response out ~100 ms

// table 1. Data. Source = await Load. Houses. Async(1, 5); // table 1.

// table 1. Data. Source = await Load. Houses. Async(1, 5); // table 1. Data. Bind(); public async Task<List<House>> Load. Houses. Async(int first, int last) { var tasks = new List<Task<House>>(); for (int i = first; i <= last; i++) { Task<House> t = House. Load. From. Database. Async(i); tasks. Add(t); } House[] loaded. Houses = await Task. When. All(tasks); return loaded. Houses. To. List(); }

public async Task<List<House>> Load. Houses. Async(int first, int last) { var loaded. Houses =

public async Task<List<House>> Load. Houses. Async(int first, int last) { var loaded. Houses = new List<House>(); var queue = new Queue<int>(Enumerable. Range(first, last – first + 1)); // Throttle the rate of issuing requests. . . var worker 1 = Worker. Async(queue, loaded. Houses); var worker 2 = Worker. Async(queue, loaded. Houses); var worker 3 = Worker. Async(queue, loaded. Houses); await Task. When. All(worker 1, worker 2, worker 3); return loaded. Houses; } private async Task Worker. Async(Queue<int> queue, List<House> results) { while (queue. Count > 0) { int i = queue. Dequeue(); var house = await House. Load. From. Database. Async(i); results. Add(house); } }

async Task Lots. Of. Work. Async() { var throttle = Throttle<string>(async message => {

async Task Lots. Of. Work. Async() { var throttle = Throttle<string>(async message => { await Task. Yield(); Console. Write. Line(message); }, max. Parallelism: Environment. Processor. Count); throttle. Post("lots"); throttle. Post("of"); throttle. Post("work"); throttle. Complete(); // Signal that we're done enqueuing work. await throttle. Completion; } static ITarget. Block<T> Throttle<T>(Func<T, Task> worker, int max) { var opts = new Execution. Dataflow. Block. Options() {Max. Degree. Of. Parallelism = max}; return new Action. Block<T>(worker, opts); }

From the method signature (how people call it) Foo(); var task = Foo. Async();

From the method signature (how people call it) Foo(); var task = Foo. Async(); From the method implementation (what resources it uses) void Foo() { for (int i=0; i<100; i++) Math. Sin(i); } async Task Foo. Async() { await client. Download. Async(); }

Synchronous Asynchronous public static void Pause. Print() { var end = Date. Time. Now

Synchronous Asynchronous public static void Pause. Print() { var end = Date. Time. Now + Time. Span. From. Seconds(10); while(Date. Time. Now < end) { } Console. Write. Line("Hello"); } public static void Task Pause. Print. Async() { return Thread. Pool. Queue. User. Work. Item(_ Task. Run(() => => Pause. Print()); } public static void Pause. Print() { Task t = Pause. Print. Async(); t. Wait(); } Task Pause. Print. Async() { public static async Task Pause. Print. Async() { var tcs = new Task. Completion. Source<bool>(); await Task. Delay(10000); new Timer(_ => { Console. Write. Line("Hello"); } tcs. Set. Result(true); }). Change(10000, Timeout. Infinite); return tcs. Task; }

Async methods: Is this true for your async methods?

Async methods: Is this true for your async methods?

synchronous asynchronous block the current thread without spawning new threads

synchronous asynchronous block the current thread without spawning new threads

Sync methods: void Foo() { Foo. Async(). Wait(); } -- will deadlock!!!

Sync methods: void Foo() { Foo. Async(). Wait(); } -- will deadlock!!!

Use Configure. Await(false) User’s app Your library async void button 1_Click(…) { Do. Work.

Use Configure. Await(false) User’s app Your library async void button 1_Click(…) { Do. Work. Async(). Wait(); await Do. Work. Async(); } async Task Do. Work. Async() { await Task. Run(. . . ). Configure. Await(false); Task. Run(. . . ); Console. Write. Line("Done task"); } Use Configure. Await(false) 2. Task. Run schedules work 3. Await captures 1. Do. Work. Async to run on thread pool Synchronization. Context and 4. UI blocks waiting for invoked on UI thread Do. Work. Async-returned hooks up a continuation to run when task completes Task to complete 6. UI thread still blocked waiting for async 5. Task. Run task completes on pool & invokes operation to complete. continuation which Posts back to UI thread Deadlock! . Configure. Await(false) avoids deadlock.

public static void Simple. Body() { Console. Write. Line("Hello, Async World!"); }. method public

public static void Simple. Body() { Console. Write. Line("Hello, Async World!"); }. method public hidebysig static void Simple. Body() cil managed {. maxstack 8 L_0000: ldstr "Hello, Async World!" L_0005: call void [mscorlib]System. Console: : Write. Line(string) L_000 a: ret }

. method public hidebysig instance void Move. Next() cil managed { // Code size

. method public hidebysig instance void Move. Next() cil managed { // Code size 66 (0 x 42). maxstack 2. locals init ([0] bool '<>t__do. Finally. Bodies', [1] class [mscorlib]System. Exception '<>t__ex'). try { IL_0000: ldc. i 4. 1 IL_0001: stloc. 0 IL_0002: ldarg. 0 IL_0003: ldfld int 32 Program/'<Simple. Body>d__0': : '<>1__state' IL_0008: ldc. i 4. m 1 public static async Task Simple. Body() { IL_0009: bne. un. s IL_000 d Console. Write. Line("Hello, Async World!"); IL_0041 IL_000 b: leave. s } IL_000 d: ldstr "Hello, Async World!" IL_0012: call void [mscorlib]System. Console: : Write. Line(string) IL_0017: leave. s IL_002 f. method public hidebysig static class [mscorlib]System. Threading. Tasks. Task Simple. Body() cil managed } { catch [mscorlib]System. Exception. custom instance void [mscorlib]System. Diagnostics. Debugger. Step. Through. Attribute: : . ctor() = ( 01 00 00 00 ) { // Code size 32 (0 x 20) IL_0019: stloc. 1. maxstack 2 IL_001 a: ldarg. 0. locals init ([0] valuetype Program/'<Simple. Body>d__0' V_0) IL_001 b: ldc. i 4. m 1 IL_0000: ldloca. s V_0 IL_001 c: stfld int 32 Program/'<Simple. Body>d__0': : '<>1__state' IL_0002: call valuetype [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder IL_0021: ldarg. 0 [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder: : Create() IL_0022: ldflda valuetype [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder IL_0007: stfld valuetype [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder Program/'<Simple. Body>d__0': : '<>t__builder' IL_000 c: ldloca. s V_0 IL_0027: ldloc. 1 IL_000 e: call instance void Program/'<Simple. Body>d__0': : Move. Next() IL_0028: call instance void [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder: : Set. Exception( IL_0013: ldloca. s V_0 class [mscorlib]System. Exception) IL_0015: ldflda valuetype [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder Program/'<Simple. Body>d__0': : '<>t__builder' IL_002 d: leave. s IL_0041 IL_001 a: call instance class [mscorlib]System. Threading. Tasks. Task [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder: : get_Task() } IL_001 f: ret IL_002 f: ldarg. 0 } IL_0030: ldc. i 4. m 1 IL_0031: stfld int 32 Program/'<Simple. Body>d__0': : '<>1__state' IL_0036: ldarg. 0 IL_0037: ldflda valuetype [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder Program/'<Simple. Body>d__0': : '<>t__builder' IL_003 c: call instance void [mscorlib]System. Runtime. Compiler. Services. Async. Task. Method. Builder: : Set. Result() IL_0041: ret }

public static async Task<int> Get. Next. Int. Async() { if (m_Count == m_Buf. Length)

public static async Task<int> Get. Next. Int. Async() { if (m_Count == m_Buf. Length) { m_Buf = await Fetch. Next. Buffer. Async(); m_Count = 0; } m_Count += 1; return m_Buf[m_Count - 1]; }

var x = await Get. Next. Int. Async(); var $awaiter = Get. Next. Int.

var x = await Get. Next. Int. Async(); var $awaiter = Get. Next. Int. Async(). Get. Awaiter(); if (!$awaiter. Is. Completed) { DO THE AWAIT/RETURN AND RESUME; } var x = $awaiter. Get. Result();

Async void is only for top-level event handlers. Use Task. Completion. Source to wrap

Async void is only for top-level event handlers. Use Task. Completion. Source to wrap Tasks around events. Use threadpool for CPU-bound code, but not IO-bound, Libraries shouldn't lie, should use Configure. Await, should be chunky.