Upload
yeardley-duke
View
26
Download
0
Embed Size (px)
DESCRIPTION
Demystifying the .NET Asynchronous Programming Landscape. Bart J.F. De Smet blogs.bartdesmet.net/bart [email protected]. It’s All About Time!. What’s asynchrony ? Greek origin a (not) syn (together with) chronos (time) Multiple parties evolving in time independently - PowerPoint PPT Presentation
Citation preview
Demystifying the .NET Asynchronous Programming LandscapeBart J.F. De Smetblogs.bartdesmet.net/[email protected]
It’s All About Time!
• What’s asynchrony?• Greek origin• a (not)• syn (together with)• chronos (time)
• Multiple parties evolving in time independently• Not being blocked
• Related concepts• Concurrency• Order in which multiple tasks execute is not determined
• Parallelism• True simultaneous execution (e.g. multicore)
It’s a Jungle Out There!
Your Program Here
Eventstriggered
I/O
completed
Packet
received
EventsCallbacks
Reactive
Nobody Likes to be Blocked
• A connected world with I/O• Network sockets• Web services• Instant messaging
• Don’t block the UI thread!• PostMessage• Control.Invoke• Dispatcher.BeginInvoke
• Asynchrony in frameworks• Silverlight• Windows Phone 7• AJAX
Language support?
Abstractions in the .NET Framework
using System;using System.IO;
class Program{ static void Main() { var buffer = new byte[4 * 1024 * 1024 /* 4MB */];
using (var fs = File.OpenRead(@“c:\temp\sample.big”)) { fs.BeginRead(buffer, 0, buffer.Length, iar => { // Process results in buffer }, null); } }}
Spot the defects
Callback using a lambda expression
Lack of closures in C# 1.0
Lifetime issues?
Need EndRead?
Abstractions in the .NET Framework
• Asynchronous Methods
• Event-Based Asynchronous Pattern
• BackgroundWorker Component
IAsyncResult BeginRead(…, AsyncCallback callback, object state);int EndRead(IAsyncResult result);
void DownloadAsync(…);event DownloadCompletedEventHandler DownloadCompleted;
void RunWorkerAsync();void ReportProgress(int percentProgress);
event DoWorkEventHandler DoWork;event ProgressChangedEventHandler ProgressChanged;event RunWorkerCompletedEventHandler RunWorkerCompleted;
Asynchronous is not unlike event-driven
Use of callback functions
The Task Parallel Library in .NET 4
Can you keep the cores busy?
Gordon Moore
True parallelism has become reality
Essential TPL Concepts – Task<T>
• Representation of a computation• Also known as a “future”
• Cheaper than threads• Continuations can be hooked up• Also known as “continuation passing style” (CPS)
Task<int> x = Task<int>.Factory.StartNew(() => { // (Long-running) computation of the result.});
x.ContinueWith(x2 => { // Code for the continuation after x completes, // with x2 an alias for the original task.});
Your application logic ends up inside out
Code runs on the CLR’s task pool
Continuations allow for sequencing
Continuations for Dummies
var report = Task.Factory.StartNew(() => GetFileData())
Returns abyte[]
.ContinueWith(x => Analyze(x.Result))
Receives aTask<byte[]>
.ContinueWith(y => Summarize(y.Result));
Data available in byte[]
What about errors? Returns a
double[]Receives a
Task<double[]>
Data Flow
Pipeline
Language Support for Asynchronous Programming – F#
13
let processAsync i = async { use stream = File.OpenRead(sprintf "Image%d.tmp" i) let! pixels = stream.AsyncRead(numPixels) let pixels' = transform pixels i use out = File.OpenWrite(sprintf "Image%d.done" i) do! out.AsyncWrite(pixels') }
let processAsyncDemo = printfn "async demo..." let tasks = [ for i in 1 .. numImages -> processAsync i ] Async.RunSynchronously (Async.Parallel tasks) |> ignore printfn "Done!"
stream.Read(numPixels, pixels -> let pixels' = transform pixels i use out = File.OpenWrite(sprintf "Image%d.done" i) do! out.AsyncWrite(pixels'))
Com
pile
r
Tran
sform
ation
(Asynchronous) Workflows in F#
• General-purpose language feature introduced by F#• Based on theory of monads• More exhaustive compared to LINQ in C# and VB• Overloadable meaning for specific keywords
• Continuation passing style• Synchronous: ‘a -> ‘b• Asynchronous:‘a -> (‘b -> unit) -> unit• In C# style: Action<T, Action<R>>
• Core concept: async { /* code */ }• Syntactic sugar for keywords inside block• E.g. let!, do!, use!
Continuation function receives result (~ ContinueWith)
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
UI Thread
Message Pump
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Asynchronous Control Flow
async void DoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); await Task.WhenAll(t1, t2); DisplayMessage("Done");}
async Task ProcessFeedAsync(string url) { var text = await DownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); await SaveDocAsync(doc); ProcessLog.WriteEntry(url);}
t1
t2
Event Processing Systems
Rx is a library for composing asynchronous
and event-based programs using observable
sequences.
( 𝑓 ◦𝑔)(𝑥 )= 𝑓 (𝑔(𝑥 ))
Queries! LINQ!
Way simpler with Rx
• .NET 3.5 SP1 and 4.0• Silverlight 3, 4, and 5• XNA 4.0 for Xbox 360• Windows Phone 7• JavaScript (RxJS)
Download at MSDN Data Developer Center or use NuGet
Environment
Mov
eNex
tGot next?
Application
OnN
ext Have next!
IEnumerable<T>IEnumerator<T>
IObservable<T>IObserver<T>
Inte
racti
ve ReactivePush-Based Data Retrieval
Event Programming Interfaces
interface IObservable<out T>{ IDisposable Subscribe(IObserver<T> observer);}
interface IObserver<in T>{ void OnNext(T value); void OnError(Exception ex); void OnCompleted();}
Both interfaces ship in the .NET 4 BCL
Observers used to define callbacks
In today’s word, errors are a given
Writing Rx Queries over Event Streams
// IObservable<string> from TextChanged eventsvar changed = Observable.FromEventPattern(txt, "TextChanged");var input = (from text in changed select ((TextBox)text.Sender).Text); .DistinctUntilChanged() .Throttle(TimeSpan.FromSeconds(1));
// Bridge with the dictionary web servicevar svc = new DictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]> (svc.BeginLookup, svc.EndLookup);
// Retrieve results and hop from stream to streamvar res = (from term in input select lookup(term)) .Switch();
Importing .NET events as observables
Bridging the async method pattern
One stream per web service request
Asynchronous Data Processing Overview
#
Synchronous Asynchronous
Sing
le v
alue
(1)
Mul
tiple
val
ues
(*)
Func<T> Task<T>
IEnumerable<T> IObservable<T>
y = f(x); y = await g(x);
Invocation expressions Await expressions
Sequencing through statements
res = from x in xs from y in q(x) …;
Composition on query expressions
foreach (var z in res) …
res.Subscribe(x => …
Imperative style code
Functional style code
Summary
• Asynchrony is everywhere• Emergence of async-only APIs• Windows Phone, Silverlight, JavaScript
• Don’t block the UI• Have to deal with latency
• Call to action• Learn about Task<T>• Download the Async CTP• http://msdn.com/vstudio/async
• Download Reactive Extensions (Rx)• http://msdn.com/data/gg577609
Stay up to date with MSDN Belux
• Register for our newsletters and stay up to date:http://www.msdn-newsletters.be• Technical updates• Event announcements and registration• Top downloads
• Follow our bloghttp://blogs.msdn.com/belux
• Join us on Facebookhttp://www.facebook.com/msdnbehttp://www.facebook.com/msdnbelux
• LinkedIn: http://linkd.in/msdnbelux/ • Twitter: @msdnbelux
Download MSDN/TechNet Desktop Gadget
http://bit.ly/msdntngadget
TechDays 2011 On-Demand
• Watch this session on-demand via Channel9http://channel9.msdn.com/belux
• Download to your favorite MP3 or video player• Get access to slides and recommended resources by the speakers