async await

23
Jeff Hart Vanishing Clouds, Inc. Async/Await for Fun and Profit Multithreading is just one damn thing after… …before, or the simultaneously with another. Scott Meyers and Andrei Alexandrescu …before March 19, 2013

Upload: jeff-hart

Post on 16-Jul-2015

139 views

Category:

Software


1 download

TRANSCRIPT

J e f f H a r t

V a n i s h i n g C l o u d s , I n c .

Async/Await for Fun and Profit

Multithreading is just one damn thing after…

…before, or the simultaneously with another.

Scott Meyers and Andrei Alexandrescu

…before

March 19, 2013

Why Multithreading?

“Modern” apps force multithreading

Desktop/client – avoiding the “toilet bowl”

Server-side scalability – all about the cores

Economics – computers not faster since P4 (90nm)

Copyright © Jeff Hart, 2015

Know Your Goal

Offloading – free the “main” thread

Still uses another (Thread Pool) thread

Works for CPU bound (i.e., thread backed)

Scaling – not using “any” thread

Still uses IO completion ports

Only works for IO bound provided by “framework”

Copyright © Jeff Hart, 2015

Domain: Prime Numbers

Natural numbers only divisible by itself c and 1for(int d=2; d<c-1; d++)…

Only even prime is 2for(int d=3; d<c-1; d+=2)…

If c/d = q, then c/q = d; and q or d ≤ SQRT(c)for(int d=3; d<=Math.Sqrt(c); d+=2)…

If c/d, then d is a prime or divisible by one<dSo only test against previously found primes

… lots of more powerful sieves

Copyright © Jeff Hart, 2015

First Attempt

Copyright © Jeff Hart, 2015

var nums = Enumerable.Range(1, Math.Sqrt(c));

var query =nums.AsParallel().Where(n => IsPrime(n));

var primes = query.ToArray();

Problems:

Doesn’t scale (parallel “never” does)

Doesn’t improve perf on a loaded system

May not improve perf “anyway”

Which Would You Prefer?

Copyright © Jeff Hart, 2015

(100s)

(100s)

(100s)

(100s)

(100s)

Synchronous

500s elapsed1 thread

(100s)

(100s)

(100s)

(100s)

(100s)

Parallel

300s elapsed2 threads

Asynchronous

100.1s elapsed1 thread

(100s)

(100s)

(100s)

(100s)

(100s)

20ms

Simple Code

Copyright © Jeff Hart, 2015

public async void Click(){var client = new AsyncSample();int answer = await client.LongAsync();txtResult.Text = "Life the universe..."

}

class AsyncSample{public async Task<int> LongAsync(){

var client = new FrameworkClass();Task task = client.LongAsync();…int result = await task;…

}}

CPU Bound IO Bound

Copyright © Jeff Hart, 2015

Needs “backing” thread

Parallel.ForEach and Task.Run

Unless writing scalable (server-side) code

Special advice to “library” writers (don’t lie/chatty)

Threads don’t increase throughput under load

Doesn’t need/want

Always use awaitrather than another (background) thread

Ying Yang

Misconceptions about async/await

Copyright © Jeff Hart, 2015

async modifier: method is async

await keyword: call the async method

and wait until it returns

suspends the thread

async modifier: method may call async methods/

use await

await keyword: call the async method and return

immediately (assuming it does); when method completes, continue from here

suspends the method (IP)

Basic ROT

Using await forces signature to: async Task[<T>]

Warning if async method without using await

await converts Task<T> to <T> (Task to void)

Method returns Task<T>, but you return T;

If you have used await

Async is cheap—but does allocate; the GC costs

State machine for method’s local variables

A delegate

Task object

Copyright © Jeff Hart, 2015

Rules

Copyright © Jeff Hart, 2015

Can’t await in catch/finally (C#6/VS15) or lock

Can’t make properties async

“Never” call async void (event handlers only)

Or if you must “fire and forget”

How Sweet the Syntactic Sugar Is

async Task<T> MyMethodAsync(«args»){var client = …var r = await client.WhateverAsync(…);… use r, as neededreturn «some expression <T>, i.e., r»;

}

async Task<T> MyMethodAsync(«args»){var tcs = TaskCompletionSource<T>();var client = …client.WhateverAsync(…).ContinueWith(task -> {

var r = task.Result;… use r, as neededtcs.SetResult(«some expression <T>, i.e., r»)

});return tcs.Task;

}

Copyright © Jeff Hart, 2015

Task Class – a Promise…

ctors – not typically used (takes Action<T>)

Properties

Factory, CreationOptions

IsCanceled, IsCompleted, IsFaulted and Status

Methods

Task.Delay – replaces Thread.Sleep

Task.Run – new in 4.5 (simple sugar)

FromResult<T>

ConfigureAwait(bool continueOnCapturedContext)

ContinueWith…, Wait…, WaitAll…, WaitAny…, Task.Yield

Copyright © Jeff Hart, 2015

Floor to Ceiling

Go down to:

Framework XxxAsync for scaling

“Creating” asynchronicity

Task.Run( { … } ) way better than worker threads

Go up to:

Handler

MSTest, etc.

Or “eat” the asynchronicity

task.ContinueWith( …, TaskContinuationOptions.Only|Not)

task.Result - blocks

Copyright © Jeff Hart, 2015

We’ve Been At This…

CLR v1: APM – Async Programming Model

Simple (mechanical) but limiting

CLR v2: EAP – Event-based Asynchronous Pattern

Very flexible but lots of “namespace noise”

CLR v4: TAP – Task-based Asynchronous Pattern

V4.5 async/await “complier sugar”

Copyright © Jeff Hart, 2015

Async Programming Model

IAsyncResult BeginDoIt(path,…, DoitCallback, doItState);

public void DoItCallback(IAsyncResult result){…var i = int EndDoIt(result);

}

int DoIt(string path,…); (inputs)

(added—optional)

Options:1. Block2. Wait Handle3. Poll4. Callback

Interface with• AsyncState• AsyncWaitHandle• IsCompleted• CompletedSynchronously

Copyright © Jeff Hart, 2015

Event-based Asynchronous Pattern

delegate void DoItCompletedEventHandler(object sender, DoItCompletedArgs args);

class DoItCompletedArgs :AsyncCompletedEventArgs{

int Result{ get; set; }

}

class MyClass{

void DoItAsync(string path,…);

Event DoItCompletedEventHandler DoItCompleted;

}

Copyright © Jeff Hart, 2015

Task-based Asynchronous Pattern

class MyClass{

async Task<int> DoItAsync(string path,…);

}

Copyright © Jeff Hart, 2015

Transitioning from APM

static Task<int> ToDoItAsync(this MyClass mc, string path,…)

{if( mc==null ) throw new ArgumentNullException(…

return Task<int> task = Task.Factory.FromAsync<int>(mc.BeginDoIt, mc.EndDoIt, path,…);

}

Copyright © Jeff Hart, 2015

Getting Real (Data)

Entity Framework 6 is TAP enabled

Secret: using System.Data.Entity;

All|AnyAsync

Count|Average|Sum|Min|MaxAsync

ContainsAsync

First|Single[OrDefault]Async

ForEachAsync

LoadAsync

ToArray|List|DictionaryAsync

Copyright © Jeff Hart, 2015

Graduation

foreach( var d in GetLotsOfData() ){DoSomethingReallyLong(d);

}

Parallel.ForEach( GetLotsOfData(), d=>{DoSomethingReallyLong(d);

}

var tasks = new List<Task>()foreach( var d in GetLotsOfData() ){

tasks.Add(DoSomethingReallyLongAsync(d));}Task.AwaitAll(tasks);

?

Copyright © Jeff Hart, 2015

Layers of Multithreading

Async/await two-step

Separating task and await

Knowin’ when to make ‘em;And knowin’ when to tend ‘em

Rules of Thumb

Mostly compiler enforced/assisted

Avoid async void (fire and forget)

Go “floor to ceiling” when possible

Task’s members to “stop”

TaskCompletionSource to “create”

The scary bit:Synchronizing (data)

Copyright © Jeff Hart, 2015

SpeakerRate.com h t t p : / / s p e a k e r r a t e . c o m / t a l k s / 5 3 5 0 1 - a s y n c - a w a i t - f o r - f u n -a n d - p r o f i t

S e a r c h f o r “ A s y n c / A w a i t f o r F u n a n d P r o f i t ”

Thank YOU!

Copyright © Jeff Hart, 2015

23