2. An other world awaits you
History of C#
C# 5.0
C# 4.0
• Async
C# 3.0 • Dynamic
• LINQ
C# 2.0 this
• Generics
C# 1.0
asynchrony
• Managed
※this is also a history of VB 7~11
3. An other world awaits you
A world which
makes no freeze
consumes low power
C# 5.0
• Async
“I could do it since years ago”
only well-trained developer could
even well-trained developer did painfully
too much cost to do
4. Agenda
Behind the async
Various asynchrony
Asynchrony in Windows 8/WinRT/.NET 4.5 era
6. C# 5.0
Asynchrony the biggest draw
async/await today’s main subject
Caller Info
CallerFilePath/CallerLineNumber/CallerMemberName属性
miscellenous changes/bug fixes
foreach variable
overload resolution
side effects from named and positional arguments
http://ufcpp.net/study/csharp/ap_ver5.html
http://msdn.microsoft.com/en-us/library/hh678682.aspx
7. 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 operation
with the same flow as synchronous
8. 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)
9. More complex example
Show multiple confirmation dialogs
confirmation flow
smithing 1
confirmation
Yes confirmationis
material 1 rare item
items
confirmation 2 checked?
on a game3
confirmation
showing result
No
confirm
【cancelled】
Yes confirmation was
material 2 smithed before
checked?
No
start!
Yes confirmation 3 limitation
already over
checked?
No
10. synchronous operation
if (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;
11. asynchronous operation (old style)
←font size is adjusted that
if (this.Check1.IsChecked ?? false)
{
Dialog.BeginShowDialog("確認 1", "1つ目の確認作業", result =>
{
if (!result)
{
whole codes fit on screen
onComplete(false);
return;
}
if (this.Check2.IsChecked ?? false)
{
Dialog.BeginShowDialog("確認 2", "2つ目の確認作業", result2 =>
{
4pt
if (!result2)
{
onComplete(false);
return;
}
if (this.Check3.IsChecked ?? false)
84 lines
{
Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>
{
onComplete(result3);
});
}
else
onComplete(true);
FYI
});
}
else if (this.Check3.IsChecked ?? false)
{
Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>
{
onComplete(result3);
});
this can be refactored with
}
else
onComplete(true);
});
}
extracting method in some
else if (this.Check2.IsChecked ?? false)
{
Dialog.BeginShowDialog("確認 2", "2つ目の確認作業", result =>
{
if (!result)
degree
{
onComplete(false);
return;
}
if (this.Check3.IsChecked ?? false)
{
more dialogs make this more
Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>
{
onComplete(result);
});
}
complex
else
onComplete(true);
});
}
else if (this.Check3.IsChecked ?? false)
{
Dialog.BeginShowDialog("確認 3", "3つ目の確認作業", result3 =>
{
onComplete(result3);
});
}
else
onComplete(true);
12. 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;
}
• just adding await operator
return true;
• easy to show more dialogs
13. Let’s enter the main subject
async/await looks powerfull, but…
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
17. Thread
Lowest layer of asynchrony
Worker1 Worker2
static void Main()
{
var t = new Thread(Worker2); shares a CPU
t.Start(); switches periodically
Worker1();
}
Preemptive multi-tasking high-intensity
coercive interruption with hardware timer
OS has privilege to switch threads
18. Thread
Lowest layer of asynchrony
But, high-intensity
for (int i = 0; i < 1000; i++)
{
var t = new Thread(Worker);
t.Start();
}
1000 threads at the same time
Thread is unsuitable to do a number of small tasks
switching(called “context switch”) has too high cost
19. Cost on creating threads
Memory
kernel state: about 1kB
local stack: about 1MB
Raising event
Thread Attached/Detached event
20. Cost on switching threads
Enter kernel mode
Save all the old thread registers
Acquire the dispatch spinlock
Determine the next thread to run fair amount of work
Leave the dispatch spinlock to perform
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
21. 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 hard to implement
lock-free algorithm by your self with thread
asynchronous (non-blocking) I/O
alternatives:
Thread Pool
I/O Completion Port
22. How to reduce the cost
Cause of the switching
scheduled interval
In .NET world
waiting handle (e.g. lock acquisition)
• do not use Thread class
waiting synchronous (blocking) I/OApps
It is removed from .NET for Windows Store
• use: Task class
How earlier version than .NET 3.5, ThraedPool class,
In to reduce
Timer class, or IAsyncResult interface
Do not create new threads hard to implement
lock-free algorithm by your self with thread
asynchronous (non-blocking) I/O
alternatives:
Thread Pool
I/O Completion Port
24. 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)
25. Thread Pool
Reuse strategy for thread
cooperative task queue
on small amount of preemptive threads
thread pool
small amount
queue
new task of threads
Task 1
ideal: same as CPU core
Task 2
enqueue tasks
before execution
…
Scheduler finds a vacant thread and posts a task to the thread
(creates a new thread only if none are vacant for a while)
26. Effort for performance
Work Stealing Queue
local queue implementation with lock-free algorithm
to prevent context switch
global local local
queue queue 1 queue 2
thread 1 thread 2
①
local queue
②
for each thread
steal a task
from others
if local queue is empty
27. FYI: lock-free algorithm
lock-based synchronization constructs
lock (_sync) depending on OS functionality
{ (needs to enter kernel mode)
_value = SomeOperation(_value);
}
lock-free(interlocked-based)
retry when race condition
long oldValue1, oldValue2; using Interlocked CPU operation※
do
{
high performance on lower racing
oldValue1 = _value;
var newValue = SomeOperation(_value);
oldValue2 = Interlocked.CompareExchange(
ref _value, newValue, oldValue1);
}
while (oldValue1 != oldValue2);
※ CPU operation which gives assurance of atomicity.
This can be performed with much lower-intensity than kernel mode constructs
29. run-through
No more wait
× lock
Thread lives, but does nothing
× synchronous (blocking) I/O • stack (1MB) not released
× Thread.Sleep • context switch triggered
• thread pool exhausted
○ asynchronous (non-blocking) I/O
○ Timer (Task.Delay) I/O Completion Port
30. I/O
Input/Output
communication between inside and outside of CPU
much slower than CPU operation by several orders
never wait!
user input
networking
CPU
storage
hardware timer
31. I/O completion port
I/O without waiting
registers callback
executes callback on thread pool after I/O completed
apps main thread thread pool
task 1
callback task 2
Thread is released just registration
…
after callback registration
I/O completion port begin I/O end I/O
hardware
32. DO use asynchronous API
Things may look alike but…
Task.Run(() => req.GetResponse());
• blocking I/O on new thread
• thread not released
req.GetResponseAsync();
• non-blocking I/O with I/O completion port
• thread released just after callback registration
33. Sleep is evel (e.g. Sleep Sort)
Sort by thread sleep proportional to value
joke algorithm
× sleep on new thread
new Thread(_ => { Thread.Sleep(t); q.Enqueue(x); }).Start();
each element needs a new thread
1MB stack per element
○timer and callback
Task.Delay(t).ContinueWith(_ => q.Enqueue(x));
34. Never provide problematic APIs
APIs on Windows 8
any method that takes more than 50 ms
is exposed as an asyncronous operation
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.
36. 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)
37. UI thread
GUI requires single-threaded execution (UI thread)
handles user input
updates graphics
UI thread another thread
ユーザー graphics
からの入力
update
OK
unable to unable to update
respond from another thread
38. Inconsistency
single-threaded
Updatable only from
UI thread
OK
Blocking UI thread
causes UI freeze
multi-threaded
39. Solution for the inconsistency
1. Offloads heavy work on thread pool
2. Returns work result to UI thread to update UI
UI thread another thread
Task.Run
heavy work
Dispatcher.Invoke
update
OK
message dispatcher
40. Code sample
In WPF※
Task.Run(() =>
{
var result = HeavyWork();
this.Dispatcher.Invoke(() =>
{
this.List.ItemsSource = result;
});
});
• Looks like difficult
• Really required?
• I want automatic dispatch. Is it possible?
※ WPF, Silverlight, and WinRT have slightly different versions
41. For automatic dispatch
Execution has a “context”
called “synchronization context”
context requirement
thread pool Tasks may be executed on any thread
Most 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
Need to capture appropriate synchronization context for
automatic dispatch
※ You can also create your own synchronization context
42. SynchronizationContext class
var context = SynchronizationContext.Current;
Task.Run(() =>
{ Capture appropriate
var result = HeavyWork();
synchronization context
context.Post(r =>
{
this.List.ItemsSource = (IEnumerable<int>)r;
}, result);
});
Is everything OK? Let’s automate!
unfortunately, no
43. 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
45. FYI: await operator
Captures synchronization context by default
default behavior (capturing synchronization context)
var result = await Task.Run(() => HeavyWork());
configuration not to capture context
var result = await Task.Run(() => HeavyWork())
.ConfigureAwait(false);
Synchronization context is captured at “await”
at user code, not inside framework
await operator can capture context even with WinRT
(native implementation)
47. Scope of await (1)
1 roundtrip, pull-based asynchronous operation
Offloading heavy work
UI thread another thread
Task.Run
heavy work
await
var result = await Task.Run(() => HeavyWork());
48. Scope of await (2)
1 roundtrip, pull-based asynchronous operation
Asynchronous (non-blocking) I/O
UI thread I/O completion port
Task.Run
begin I/O
await
end I/O
var result = await client.GetAsync();
49. Scope of await (3)
1 roundtrip, pull-based asynchronous operation
showing dialog box
UI thread GUI framework
show dialog
user interaction with dialog
OK
await
var result = await dialog.ShowAsync();
No way to nest UI thread
UI thread must be released before user interaction
50. Out of scope
parallelism
asynchronous event stream
complex dataflow
51. parallelism
Demand to use power of whole CPU core
Parallel class
Parallel.ForEach(data, x =>
{
// operation in parallel
});
Parallel LINQ
var results = data.AsParallel()
.Select(x => /* operation in parallel */);
53. event stream-based API in WinRT
Event raised on native code
× automatic dispatch to .NET apps
void Init()
{
var sensor = Accelerometer.GetDefault();
sensor.Shaken += sensor_Shaken;
}
void sensor_Shaken(
Accelerometer sender,
AccelerometerShakenEventArgs args)
{
// event handling requires explicit
use of
}
Dispatcher.Post
54. event stream-based API in WinRT
Recommended: Rx※
var sensor = Accelerometer.GetDefault();
Observable.FromEventPattern(sensor, "Shaken")
.ObserveOn(SynchronizationContext.Current)
.Subscribe(args =>
{
// event handling similar to TaskScheduler
});
※ Reactive Extensions
http://msdn.microsoft.com/en-us/data/gg577609
NuGet-able, applicable to Windows Store Apps
55. 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
58. run-through
No more wait task.ContinueWith(
use callback callback);
suspend and resume same as iterator
Synchronization context
59. 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:
IEnumerable<int> Method()
{ Current = 1;
_state = 1;
yield return 1; return true;
case 1:
Current = 2;
yield return 2; _state = 2;
return true;
case 2:
default:
} return false;
}
}
}
60. 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:
save state
IEnumerable<int> Method() Current = 1;
{ Current = 1;
yield return 1;
_state = 1;
_state = 1;
return true;
return 1:
case true; suspend
case 1: = 2;
Current
return true; label for resume
yield return 2; _state = 2;
case 2:
default:
} return false;
}
}
}
61. How to await (conceptual)
Iterator + ContinueWith
save state
_state = 1;
if (!task1.IsCompleted)
async Task<int> Method() {
{ task1.ContinueWith(a);
var x = await task1;
var y = await task2; return; suspend
} }
case 1: label for resume
var x = task1.Result;
get result
62. 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); • Awaiter captures
return; synchronization context
} • You can create your own
case 1: awaiter
var x = awaiter1.GetResult();
• Any type can be awaitable
63. On the contrary
If unable to use C# 5.0
You can use iterator for asynchronous operation
but painful
If unable to use C# (any version)
You can implement IEnumerable-like operation by
yourself for asynchronous operation
extremely painful
but performant
I eager to use C#, really…