Upload
-
View
1.083
Download
0
Tags:
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
An other world awaits youUnavoidable new world: async
++C++; // Nobuyuki IWANAGA
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
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
Agenda Behind the async
Various asynchrony
Asynchrony in Windows 8/WinRT/.NET 4.5 era
async/awaitwarming up
Power of C# 5.0/VB 11
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
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
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)
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!
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;
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);
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
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…
infrastructure of asynchronous operationThread Pool, I/O Completion Port, Synchronization Context
Infrastructures for asynchrony Thread
Thread Pool
I/O Completion Port
Synchronization Context
Infrastructures for asynchrony Thread
Thread Pool
I/O Completion Port
Synchronization Context
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
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
Cost on creating threads Memory
kernel state: about 1kB
local stack: about 1MB
Raising event Thread Attached/Detached event
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
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
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
Infrastructures for asynchrony Thread
Thread Pool
I/O Completion Port
Synchronization Context
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)
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
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
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
Infrastructures for asynchrony Thread
Thread Pool
I/O Completion Port
Synchronization Context
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
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
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
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();
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
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
Infrastructures for asynchrony Thread
Thread Pool
I/O Completion Port
Synchronization Context
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)
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
Inconsistency
Updatable only fromUI thread
Blocking UI threadcauses UI freeze
single-threaded
multi-threaded
OK
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
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?
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
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
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
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
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);
Various Asynchronyawait is not silver bullet
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());
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();
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
Out of scope parallelism
asynchronous event stream
complex dataflow
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});
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
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
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
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
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
how to awaitdeep dive into async/await
run-through No more wait
use callback
suspend and resume
Synchronization context
task.ContinueWith( callback);
same as iterator
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;
}
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
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
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
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…
Conclusion
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