65
An other world awaits you Unavoidable new world: async ++C++; // Nobuyuki IWANAGA

An other world awaits you

  • Upload
    -

  • View
    1.083

  • Download
    0

Embed Size (px)

DESCRIPTION

Talks about async/await, new feature in C# 5.0/VB 11 •Behind the async •Various asynchrony •Asynchrony in Windows 8/WinRT/.NET 4.5 era

Citation preview

Page 1: An other world awaits you

An other world awaits youUnavoidable new world: async

++C++; // Nobuyuki IWANAGA

Page 2: An other world awaits you

An other world awaits you History of C#

C# 1.0• Manage

d

C# 2.0• Generic

s

C# 3.0• LINQ

C# 4.0• Dynami

c

C# 5.0• Async

this

asynchrony

※this is also a history of VB 7 ~ 11

Page 3: An other world awaits you

C# 5.0• Async

An other world awaits you A world which

makes no freeze

consumes low power

“I could do it since years ago” only well-trained developer could

even well-trained developer did painfully

too much cost to do

Page 4: An other world awaits you

Agenda Behind the async

Various asynchrony

Asynchrony in Windows 8/WinRT/.NET 4.5 era

Page 5: An other world awaits you

async/awaitwarming up

Power of C# 5.0/VB 11

Page 6: An other world awaits you

C# 5.0 Asynchrony

async/await

Caller Info CallerFilePath/CallerLineNumber/

CallerMemberName 属性

miscellenous changes/bug fixes foreach variable

overload resolution

side effects from named and positional arguments

the biggest drawtoday’s main

subject

http://ufcpp.net/study/csharp/ap_ver5.htmlhttp://msdn.microsoft.com/en-us/library/hh678682.aspx

Page 7: An other world awaits you

C# 5.0 の async/await Task class

async modifier

await operator

async Task<string> GetAsync(string url){ var client = new HttpClient(); var res = await client.GetAsync(url); var content = await res.Content.ReadAsStringAsync(); return content;}

asynchronous operationwith the same flow as synchronous

Page 8: An other world awaits you

await

t.Wait();

• wait for t: synonym is “stay”• stay on a thread (blocking execution)

await t;

• await t: synonym is “expect”• expect to get callback (non-blocking)

Page 9: An other world awaits you

Show multiple confirmation dialogs

More complex example

checked?

checked?

checked?

No

No

Yes

Yes

Yes

confirmation flow

showing result

No

confirm

confirmation 1

confirmation 2

confirmation 3

smithingitemson a game

confirmation 1

confirmation 2

confirmation 3

material is rare item

material was smithed before

already over limitation

【 cancelled】

start!

Page 10: An other world awaits you

synchronous operationif (this.Check1.IsChecked ?? false){

var result = Dialog.ShowDialog("confirmation 1");if (!result) return false;

} if (this.Check2.IsChecked ?? false){

var result = Dialog.ShowDialog("confirmation 2");if (!result) return false;

} if (this.Check3.IsChecked ?? false){

var result = Dialog.ShowDialog("confirmation 3");if (!result) return false;

} return true;

Page 11: An other world awaits you

asynchronous operation (old style) ←font size is adjusted

that whole codes fit on screen 4pt

84 lines

FYI this can be refactored with

extracting method in some degree

more dialogs make this more complex

if (this.Check1.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 1", "1 つ目の確認作業 ", result =>{

if (!result){

onComplete(false);return;

if (this.Check2.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 2", "2 つ目の確認作業 ", result2 =>{

if (!result2){

onComplete(false);return;

if (this.Check3.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 3", "3 つ目の確認作業 ", result3 =>{

onComplete(result3);});

}else

onComplete(true);});

}else if (this.Check3.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 3", "3 つ目の確認作業 ", result3 =>{

onComplete(result3);});

}else

onComplete(true);});

}else if (this.Check2.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 2", "2 つ目の確認作業 ", result =>{

if (!result){

onComplete(false);return;

if (this.Check3.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 3", "3 つ目の確認作業 ", result3 =>{

onComplete(result);});

}else

onComplete(true);});

}else if (this.Check3.IsChecked ?? false){

Dialog.BeginShowDialog(" 確認 3", "3 つ目の確認作業 ", result3 =>{

onComplete(result3);});

}else

onComplete(true); 

Page 12: An other world awaits you

asynchronous operation ( C# 5.0 )if (this.Check1.IsChecked ?? false){

var result = await Dialog.ShowDialogAsync("confirmation 1");if (!result) return false;

} if (this.Check2.IsChecked ?? false){

var result = await Dialog.ShowDialogAsync("confirmation 2");if (!result) return false;

} if (this.Check3.IsChecked ?? false){

var result = await Dialog.ShowDialogAsync("confirmation 3");if (!result) return false;

} return true;

• just adding await operator

• easy to show more dialogs

Page 13: An other world awaits you

Let’s enter the main subject

What’s behind it? infrastructure of asynchronous operation

deep dive into await operator

Is the await operator good at everything? no

parallelism

asynchronous event stream

complex dataflow

async/await looks powerfull, but…

Page 14: An other world awaits you

infrastructure of asynchronous operationThread Pool, I/O Completion Port, Synchronization Context

Page 15: An other world awaits you

Infrastructures for asynchrony Thread

Thread Pool

I/O Completion Port

Synchronization Context

Page 16: An other world awaits you

Infrastructures for asynchrony Thread

Thread Pool

I/O Completion Port

Synchronization Context

Page 17: An other world awaits you

Thread Lowest layer of asynchrony

Preemptive multi-tasking coercive interruption with hardware timer

OS has privilege to switch threads

static void Main(){ var t = new Thread(Worker2); t.Start(); Worker1();}

Worker1 Worker2

shares a CPUswitches periodically

high-intensity

Page 18: An other world awaits you

Thread Lowest layer of asynchrony

But, high-intensity

Thread is unsuitable to do a number of small tasks switching ( called “context switch” ) has too high

cost

for (int i = 0; i < 1000; i++){ var t = new Thread(Worker); t.Start();}

1000 threads at the same time

Page 19: An other world awaits you

Cost on creating threads Memory

kernel state: about 1kB

local stack: about 1MB

Raising event Thread Attached/Detached event

Page 20: An other world awaits you

Cost on switching threads Enter kernel mode

Save all the old thread registers

Acquire the dispatch spinlock

Determine the next thread to run

Leave the dispatch spinlock

Swap the threads kernel state

Restore the new threads registers

Leave kernel mode

※ http://blogs.msdn.com/b/larryosterman/archive/2005/01/05/347314.aspx

fair amount of workto perform

Page 21: An other world awaits you

How to reduce the cost Cause of the switching

scheduled interval

waiting handle (e.g. lock acquisition ) waiting synchronous (blocking) I/O

How to reduce Do not create new threads

lock-free algorithm

asynchronous (non-blocking) I/O

hard to implementby your self with thread

alternatives:Thread PoolI/O Completion Port

Page 22: An other world awaits you

How to reduce the cost Cause of the switching

scheduled interval

waiting handle (e.g. lock acquisition ) waiting synchronous (blocking) I/O

How to reduce Do not create new threads

lock-free algorithm

asynchronous (non-blocking) I/O

hard to implementby your self with thread

alternatives:Thread PoolI/O Completion Port

In .NET world• do not use Thread class

• use: Task class

It is removed from .NET for Windows Store Apps

In earlier version than .NET 3.5, ThraedPool class,Timer class, or IAsyncResult interface

Page 23: An other world awaits you

Infrastructures for asynchrony Thread

Thread Pool

I/O Completion Port

Synchronization Context

Page 24: An other world awaits you

2 kinds of multi-tasking

Preemptive

• coercive interruption with hardware timer• OS has privileges to switch threads• Pros.: fair (OS equally take control away from tasks )• Cons.: high-intensity (switching cost and memory consumption)

Cooperative

• each task take responsibility• A task can start after another task finished• Pros.: low-intensity• Cons.: unfair (One bad task could freeze whole system)

Page 25: An other world awaits you

Thread Pool Reuse strategy for thread

cooperative task queue

on small amount of preemptive threads

thread pool

queueTask 1

Task 2

small amount of threads

Scheduler finds a vacant thread and posts a task to the thread

(creates a new thread only if none are vacant for a while)

new task

enqueue tasksbefore

execution

ideal: same as CPU core

Page 26: An other world awaits you

Effort for performance Work Stealing Queue

local queue implementation with lock-free algorithm

to prevent context switch

localqueue 1

localqueue 2

thread 1 thread 2

globalqueue

①local queuefor each thread

②steal a taskfrom othersif local queue is empty

Page 27: An other world awaits you

FYI: lock-free algorithm

lock (_sync){    _value = SomeOperation(_value);}

long oldValue1, oldValue2;do{    oldValue1 = _value;    var newValue = SomeOperation(_value);    oldValue2 = Interlocked.CompareExchange( ref _value, newValue, oldValue1);}while (oldValue1 != oldValue2);

lock-based

lock-free ( interlocked-based )

synchronization constructs depending on OS

functionality(needs to enter kernel

mode)

retry when race conditionusing Interlocked CPU

operation※

high performance on lower racing

※ CPU operation which gives assurance of atomicity.This can be performed with much lower-intensity than kernel mode constructs

Page 28: An other world awaits you

Infrastructures for asynchrony Thread

Thread Pool

I/O Completion Port

Synchronization Context

Page 29: An other world awaits you

run-through No more wait

× lock

× synchronous (blocking) I/O

× Thread.Sleep

○ asynchronous (non-blocking) I/O

○ Timer (Task.Delay)

Thread lives, but does nothing• stack (1MB) not released• context switch triggered• thread pool exhausted

I/O Completion Port

Page 30: An other world awaits you

I/O Input/Output

communication between inside and outside of CPU

much slower than CPU operation by several orders

user input

networking

storage

CPU

never wait!

hardware timer

Page 31: An other world awaits you

I/O completion port I/O without waiting

registers callback

executes callback on thread pool after I/O completed

thread pool

task 1

task 2

main threadapps

I/O completion port

hardware

begin I/O end I/O

callbackregistration

Thread is released just after callback registration

Page 32: An other world awaits you

DO use asynchronous API Things may look alike but…

• blocking I/O on new thread• thread not released

Task.Run(() => req.GetResponse());

• non-blocking I/O with I/O completion port• thread released just after callback registration

req.GetResponseAsync();

Page 33: An other world awaits you

Sleep is evel (e.g. Sleep Sort) Sort by thread sleep proportional to value

joke algorithm

new Thread(_ => { Thread.Sleep(t); q.Enqueue(x); }).Start();

Task.Delay(t).ContinueWith(_ => q.Enqueue(x));

× sleep on new thread

○timer and callback

each element needs a new thread

1MB stack per element

Page 34: An other world awaits you

Never provide problematic APIs APIs on Windows 8

WinRT Storage, Networking, Graphics

Launcher, Popups

brand-new class in .NET 4.5 e.g. HttpClient

.NET for Windows Store Apps removal of blocking I/O API, Thread class, etc.

any method that takes more than 50 ms is exposed as an asyncronous operation

Page 35: An other world awaits you

Infrastructures for asynchrony Thread

Thread Pool

I/O Completion Port

Synchronization Context

Page 36: An other world awaits you

Single thread required Thread safety costs high-intensity

Several framework requires single-threaded execution typical example: GUI

GUI framework (not only C#/.NET) requires single threaded

same applies to low-level graphics APIs (including DirectX, OpenGL)

Page 37: An other world awaits you

UI thread GUI requires single-threaded execution (UI

thread) handles user input

updates graphicsUI thread

ユーザーからの入力

OK

graphics

update

another thread

unable to

respond

unable to update from another

thread

Page 38: An other world awaits you

Inconsistency

Updatable only fromUI thread

Blocking UI threadcauses UI freeze

single-threaded

multi-threaded

OK

Page 39: An other world awaits you

Solution for the inconsistency1. Offloads heavy work on thread pool

2. Returns work result to UI thread to update UI

UI thread

OK

update

another thread

heavy work

Dispatcher.Invoke

Task.Run

message dispatcher

Page 40: An other world awaits you

Code sample In WPF※

Task.Run(() =>{    var result = HeavyWork();

    this.Dispatcher.Invoke(() =>    {        this.List.ItemsSource = result;    });});

※ WPF, Silverlight, and WinRT have slightly different versions

• Looks like difficult• Really required?• I want automatic dispatch. Is it

possible?

Page 41: An other world awaits you

For automatic dispatch Execution has a “context”

called “synchronization context”

Need to capture appropriate synchronization context for automatic dispatch

context requirement

thread pool Tasks may be executed on any threadMost important thing is performance

GUI Task must be executed on UI thread to update UI

Web API Tasks must be executed with the identity and culture of the Web request

※ You can also create your own synchronization context

Page 42: An other world awaits you

SynchronizationContext class

Is everything OK? Let’s automate!

var context = SynchronizationContext.Current;

Task.Run(() =>{    var result = HeavyWork();

    context.Post(r =>    {        this.List.ItemsSource = (IEnumerable<int>)r;    }, result);});

Capture appropriate synchronization context

unfortunately, no

Page 43: An other world awaits you

Problem UI context cannot be captured from thread

pool crash when BackgroundWorker starts another

BackgroundWorker

Message dispatch to UI thread has performance hit tasks should be executed on thread pool as much

as possible for perfomance

Native ⇔ .NET WinRT XAML UI (native implementation) cannot

automate capture synchronization context for .NET apps JavaScript has no problem to automate

The reason is:• single purpose, single framework, single context• small requirement on performance

Page 44: An other world awaits you

Thus, options required TaskSchduler options

Task.Run(() => HeavyWork())    .ContinueWith(t =>    {        // executed on thread pool    });

Task.Run(() => HeavyWork())    .ContinueWith(t =>    {        // executed on UI thread    }, TaskScheduler.FromCurrentSynchronizationContext());

default scheduler (thread pool)

scheduler capturing synchronization context

Page 45: An other world awaits you

FYI: await operator Captures synchronization context by default

Synchronization context is captured at “await” at user code, not inside framework

await operator can capture context even with WinRT (native implementation)

var result = await Task.Run(() => HeavyWork());

default behavior (capturing synchronization context)

configuration not to capture contextvar result = await Task.Run(() => HeavyWork())     .ConfigureAwait(false);

Page 46: An other world awaits you

Various Asynchronyawait is not silver bullet

Page 47: An other world awaits you

Scope of await (1) 1 roundtrip, pull-based asynchronous

operationOffloading heavy workUI thread another thread

heavy work

await

Task.Run

var result = await Task.Run(() => HeavyWork());

Page 48: An other world awaits you

Scope of await (2) 1 roundtrip, pull-based asynchronous

operationAsynchronous (non-blocking) I/OUI thread I/O completion port

await

Task.Runbegin I/O

end I/O

var result = await client.GetAsync();

Page 49: An other world awaits you

Scope of await (3) 1 roundtrip, pull-based asynchronous

operationshowing dialog boxUI thread

await

show dialog

OKuser interaction with dialog

GUI framework

var result = await dialog.ShowAsync();

No way to nest UI threadUI thread must be released before user interaction

Page 50: An other world awaits you

Out of scope parallelism

asynchronous event stream

complex dataflow

Page 51: An other world awaits you

parallelism Demand to use power of whole CPU core

Parallel class

Parallel LINQvar results = data.AsParallel()    .Select(x => /* operation in parallel */);

Parallel.ForEach(data, x =>{    // operation in parallel});

Page 52: An other world awaits you

asynchronous event stream multiple data, push-based

sensor API

push notification from server

user interaction (GUI event)

eventconsumer

resister handler

eventsource

notify event

void Init(){    var sensor = Accelerometer.GetDefault();    sensor.Shaken += sensor_Shaken;}

void sensor_Shaken( Accelerometer sender,  AccelerometerShakenEventArgs args){    // event handling}

notify event

notify event

notify event

Page 53: An other world awaits you

event stream-based API in WinRT Event raised on native code

× automatic dispatch to .NET appsvoid Init(){    var sensor = Accelerometer.GetDefault();    sensor.Shaken += sensor_Shaken;}

void sensor_Shaken( Accelerometer sender,  AccelerometerShakenEventArgs args){    // event handling}

requires explicit use of Dispatcher.Post

Page 54: An other world awaits you

event stream-based API in WinRT Recommended: Rx※

var sensor = Accelerometer.GetDefault();

Observable.FromEventPattern(sensor, "Shaken")    .ObserveOn(SynchronizationContext.Current)    .Subscribe(args =>    {        // event handling    });

※ Reactive Extensionshttp://msdn.microsoft.com/en-us/data/gg577609NuGet-able, applicable to Windows Store Apps

similar to TaskScheduler

Page 55: An other world awaits you

complex dataflow Await operator achieves asynchrous with

same control flow as synchronous operation

If flow is complex on synchronous, it is also complex on asynchronous with await two-dimensional dataflow

state machine

Page 56: An other world awaits you

complex dataflow Recommended:

WF (Windows Workflow Foundation) http://msdn.microsoft.com/en-us/vstudio/aa663328

TPL Dataflow http://

msdn.microsoft.com/en-us/devlabs/gg585582.aspx

Page 57: An other world awaits you

how to awaitdeep dive into async/await

Page 58: An other world awaits you

run-through No more wait

use callback

suspend and resume

Synchronization context

task.ContinueWith( callback);

same as iterator

Page 59: An other world awaits you

Iterator suspend and resume

class MethodEnumerator : IEnumerator<int>{    public int Current { get; private set; }    private int _state = 0;     public bool MoveNext()    {        switch (_state)        {            case 0:             Current = 1;            _state = 1;            return true;            case 1:             Current = 2;            _state = 2;            return true;            case 2:             default:            return false;        }    }}

IEnumerable<int> Method(){    yield return 1;

    yield return 2;

}

Page 60: An other world awaits you

Iterator suspend and resume

class MethodEnumerator : IEnumerator<int>{    public int Current { get; private set; }    private int _state = 0;     public bool MoveNext()    {        switch (_state)        {            case 0:             Current = 1;            _state = 1;            return true;            case 1:             Current = 2;            _state = 2;            return true;            case 2:             default:            return false;        }    }}

IEnumerable<int> Method(){    yield return 1;

    yield return 2;

}

Current = 1;_state = 1;return true;case 1:

save state

suspend

label for resume

Page 61: An other world awaits you

How to await (conceptual) Iterator + ContinueWith

async Task<int> Method(){    var x = await task1;    var y = await task2;}

_state = 1;if (!task1.IsCompleted){    task1.ContinueWith(a);    return;}case 1:var x = task1.Result;

suspend

save state

get result

label for resume

Page 62: An other world awaits you

How to await In fact, bit more complex

Abstraction with awaiter ( awaitable pattern )

_state = 1;var awaiter1 = task1.GetAwaiter();if (!awaiter1.IsCompleted){    awaiter1.OnCompleted(a);    return;}case 1:var x = awaiter1.GetResult();

• Awaiter captures synchronization context• You can create your own

awaiter• Any type can be

awaitable

Page 63: An other world awaits you

On the contrary If unable to use C# 5.0

You can use iterator for asynchronous operation

If unable to use C# (any version) You can implement IEnumerable-like operation by

yourself for asynchronous operation

but painful

extremely painfulbut performant

I eager to use C#, really…

Page 64: An other world awaits you

Conclusion

Page 65: An other world awaits you

Conclusion Do not use thread (Thread class)

use thread pool (Task class)

await × wait (stay), ○ await (expect)

iterator (suspend and resume) + ContinueWith (callback)

synchronization context

await is not silver bullet parallelism, asynchronous event stream

complex dataflow